mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Fleet] Implement single actions in new installed integrations UI (#217584)
This commit is contained in:
parent
5080c5facb
commit
0cf0e75c9c
12 changed files with 778 additions and 266 deletions
|
@ -34,12 +34,7 @@ export const LicenseModal: React.FunctionComponent<Props> = ({
|
|||
}) => {
|
||||
const { notifications } = useStartServices();
|
||||
|
||||
const {
|
||||
data: licenseResponse,
|
||||
error: licenseError,
|
||||
isLoading,
|
||||
} = useGetFileByPathQuery(licensePath);
|
||||
const licenseText = licenseResponse?.data;
|
||||
const { data: licenseText, error: licenseError, isLoading } = useGetFileByPathQuery(licensePath);
|
||||
|
||||
if (licenseError) {
|
||||
notifications.toasts.addError(licenseError, {
|
||||
|
|
|
@ -48,11 +48,10 @@ export const ChangelogModal: React.FunctionComponent<Props> = ({
|
|||
const { notifications } = useStartServices();
|
||||
|
||||
const {
|
||||
data: changelogResponse,
|
||||
data: changelogText,
|
||||
error: changelogError,
|
||||
isLoading,
|
||||
} = useGetFileByPathQuery(`/package/${packageName}/${latestVersion}/changelog.yml`);
|
||||
const changelogText = changelogResponse?.data;
|
||||
|
||||
// currentVersion is used to display the changelog up to the current installed version, when there is a newer one available
|
||||
const finalChangelog = currentVersion
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { EuiCallOut, EuiConfirmModal } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
|
||||
|
@ -18,23 +19,43 @@ export const ConfirmBulkUninstallModal: React.FunctionComponent<{
|
|||
}> = ({ onClose, onConfirm, selectedItems }) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const isSingleItem = selectedItems.length === 1;
|
||||
|
||||
return (
|
||||
<EuiConfirmModal
|
||||
title={i18n.translate('xpack.fleet.installedIntegrations.bulkUninstallModal.title', {
|
||||
defaultMessage: 'Uninstall {countIntegrations} integrations ',
|
||||
values: {
|
||||
countIntegrations: selectedItems.length,
|
||||
},
|
||||
})}
|
||||
title={
|
||||
isSingleItem
|
||||
? i18n.translate('xpack.fleet.installedIntegrations.bulkUninstallModal.singleTitle', {
|
||||
defaultMessage: 'Uninstall {integrationName} ',
|
||||
values: {
|
||||
integrationName: selectedItems[0].title,
|
||||
},
|
||||
})
|
||||
: i18n.translate('xpack.fleet.installedIntegrations.bulkUninstallModal.title', {
|
||||
defaultMessage: 'Uninstall {countIntegrations} integrations ',
|
||||
values: {
|
||||
countIntegrations: selectedItems.length,
|
||||
},
|
||||
})
|
||||
}
|
||||
confirmButtonText={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUninstallModal.confirmButton',
|
||||
{ defaultMessage: 'Uninstall integrations' }
|
||||
{
|
||||
defaultMessage: 'Uninstall {itemsCount, plural, one {integration} other {integrations}} ',
|
||||
values: { itemsCount: selectedItems.length },
|
||||
}
|
||||
)}
|
||||
buttonColor="danger"
|
||||
cancelButtonText={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUninstallModal.cancelButton',
|
||||
{ defaultMessage: 'Review and edit selection' }
|
||||
)}
|
||||
cancelButtonText={
|
||||
isSingleItem
|
||||
? i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUninstallModal.cancelSingleButton',
|
||||
{ defaultMessage: 'Cancel' }
|
||||
)
|
||||
: i18n.translate('xpack.fleet.installedIntegrations.bulkUninstallModal.cancelButton', {
|
||||
defaultMessage: 'Review and edit selection',
|
||||
})
|
||||
}
|
||||
onCancel={onClose}
|
||||
isLoading={isLoading}
|
||||
onConfirm={async () => {
|
||||
|
@ -53,14 +74,19 @@ export const ConfirmBulkUninstallModal: React.FunctionComponent<{
|
|||
title={i18n.translate('xpack.fleet.installedIntegrations.bulkUninstallModal.calloutTitle', {
|
||||
defaultMessage: 'This action cannot be undone.',
|
||||
})}
|
||||
content={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUninstallModal.calloutContent',
|
||||
{
|
||||
defaultMessage:
|
||||
'All Kibana and Elasticsearch assets created by these integrations will be also removed. Review and edit your selection if needed.',
|
||||
}
|
||||
>
|
||||
{isSingleItem ? (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUninstallModal.calloutContentSingleItem"
|
||||
defaultMessage="All Kibana and Elasticsearch assets created by this integration will be also removed."
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUninstallModal.calloutContent"
|
||||
defaultMessage="All Kibana and Elasticsearch assets created by these integrations will be also removed. Review and edit your selection if needed."
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
</EuiConfirmModal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,46 +7,89 @@
|
|||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiAccordion,
|
||||
EuiCodeBlock,
|
||||
EuiConfirmModal,
|
||||
EuiFormRow,
|
||||
EuiIcon,
|
||||
EuiPanel,
|
||||
EuiSkeletonText,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { useGetFileByPathQuery } from '../../../../../../../hooks';
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
|
||||
export const ViewChangelog: React.FunctionComponent<{
|
||||
pkgName: string;
|
||||
pkgVersion: string;
|
||||
}> = ({ pkgName, pkgVersion }) => {
|
||||
const { data: changelogText, isLoading } = useGetFileByPathQuery(
|
||||
`/package/${pkgName}/${pkgVersion}/changelog.yml`
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiSkeletonText lines={5} size="s" isLoading={isLoading} contentAriaLabel="changelog text">
|
||||
<EuiCodeBlock overflowHeight={150}>{changelogText}</EuiCodeBlock>
|
||||
</EuiSkeletonText>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfirmBulkUpgradeModal: React.FunctionComponent<{
|
||||
selectedItems: InstalledPackageUIPackageListItem[];
|
||||
onClose: () => void;
|
||||
onConfirm: (params: { updatePolicies: boolean }) => void;
|
||||
}> = ({ onClose, onConfirm, selectedItems }) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const [updatePolicies, setUpdatePolicies] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const isSingleItem = selectedItems.length === 1;
|
||||
|
||||
return (
|
||||
<EuiConfirmModal
|
||||
title={i18n.translate('xpack.fleet.installedIntegrations.bulkUpgradeModal.title', {
|
||||
defaultMessage: 'Upgrade {countIntegrations} integrations and {countPolicies} policies',
|
||||
values: {
|
||||
countIntegrations: selectedItems.length,
|
||||
countPolicies: selectedItems.reduce(
|
||||
(acc, item) => acc + (item.packagePoliciesInfo?.count ?? 0),
|
||||
0
|
||||
),
|
||||
},
|
||||
})}
|
||||
title={
|
||||
isSingleItem
|
||||
? i18n.translate('xpack.fleet.installedIntegrations.bulkUpgradeModal.title', {
|
||||
defaultMessage: 'Upgrade {pkgName} and policies',
|
||||
values: {
|
||||
pkgName: selectedItems[0].title,
|
||||
},
|
||||
})
|
||||
: i18n.translate('xpack.fleet.installedIntegrations.bulkUpgradeModal.title', {
|
||||
defaultMessage:
|
||||
'Upgrade {countIntegrations} integrations and {countPolicies} policies',
|
||||
values: {
|
||||
countIntegrations: selectedItems.length,
|
||||
countPolicies: selectedItems.reduce(
|
||||
(acc, item) => acc + (item.packagePoliciesInfo?.count ?? 0),
|
||||
0
|
||||
),
|
||||
},
|
||||
})
|
||||
}
|
||||
confirmButtonText={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUpgradeModal.confirmButton',
|
||||
{ defaultMessage: 'Upgrade to latest version' }
|
||||
)}
|
||||
cancelButtonText={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUpgradeModal.cancelButton',
|
||||
{ defaultMessage: 'Review integration selection' }
|
||||
)}
|
||||
cancelButtonText={
|
||||
isSingleItem
|
||||
? i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUpgradeModal.cancelSingleItemButton',
|
||||
{
|
||||
defaultMessage: 'Cancel',
|
||||
}
|
||||
)
|
||||
: i18n.translate('xpack.fleet.installedIntegrations.bulkUpgradeModal.cancelButton', {
|
||||
defaultMessage: 'Review integration selection',
|
||||
})
|
||||
}
|
||||
onCancel={onClose}
|
||||
isLoading={isLoading}
|
||||
onConfirm={async () => {
|
||||
|
@ -60,39 +103,87 @@ export const ConfirmBulkUpgradeModal: React.FunctionComponent<{
|
|||
}}
|
||||
>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.description"
|
||||
defaultMessage={
|
||||
'We will upgrade your integrations and policies to the latest available version.'
|
||||
}
|
||||
/>
|
||||
{isSingleItem ? (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.singleItemDescription"
|
||||
defaultMessage={
|
||||
'We will upgrade this integration and policies to the latest available version.'
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.description"
|
||||
defaultMessage={
|
||||
'We will upgrade your integrations and policies to the latest available version.'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</EuiText>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiSwitch
|
||||
checked={updatePolicies}
|
||||
onChange={(e) => {
|
||||
setUpdatePolicies(e.target.checked);
|
||||
}}
|
||||
label={
|
||||
{isSingleItem ? (
|
||||
<>
|
||||
<EuiText color="subdued" size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.policiesSwitchLabel"
|
||||
defaultMessage="Upgrade integration policies"
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.installedVersionText"
|
||||
defaultMessage={'Installed version: {installedVersion}'}
|
||||
values={{
|
||||
installedVersion: <b>{selectedItems[0].installationInfo!.version}</b>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiCallOut
|
||||
iconType="iInCircle"
|
||||
title={i18n.translate(
|
||||
'xpack.fleet.installedIntegrations.bulkUpgradeModal.policiesCallout',
|
||||
{
|
||||
defaultMessage:
|
||||
'When enabled, Fleet will attempt to upgrade and deploy integration policies automatically.',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText color="subdued" size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.latestVersionText"
|
||||
defaultMessage={'Latest version available: {latestVersion}'}
|
||||
values={{
|
||||
latestVersion: <b>{selectedItems[0].version}</b>,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiAccordion
|
||||
id="viewChangelog"
|
||||
buttonContent={
|
||||
<EuiTextColor color={euiTheme.colors.link}>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.viewChangelogButton"
|
||||
defaultMessage="View Changelog"
|
||||
/>
|
||||
</EuiTextColor>
|
||||
}
|
||||
>
|
||||
<ViewChangelog pkgName={selectedItems[0].name} pkgVersion={selectedItems[0].version} />
|
||||
</EuiAccordion>
|
||||
<EuiSpacer size="l" />
|
||||
</>
|
||||
) : null}
|
||||
<EuiPanel hasShadow={false} hasBorder={false} color="subdued">
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiSwitch
|
||||
data-test-subj="upgradeIntegrationsPoliciesSwitch"
|
||||
checked={updatePolicies}
|
||||
onChange={(e) => {
|
||||
setUpdatePolicies(e.target.checked);
|
||||
}}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.policiesSwitchLabel"
|
||||
defaultMessage="Upgrade integration policies"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="iInCircle" size="m" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.installedIntegrations.bulkUpgradeModal.policiesCallout"
|
||||
defaultMessage="When enabled, Fleet will attempt to upgrade and deploy integration policies automatically."
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiPanel>
|
||||
</EuiConfirmModal>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'
|
|||
import { useAuthz } from '../../../../../../../hooks';
|
||||
import type { InstallFailedAttempt } from '../../../../../../../../common/types';
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
import { useInstalledIntegrationsActions } from '../hooks/use_installed_integrations_actions';
|
||||
|
||||
import { DisabledWrapperTooltip } from './disabled_wrapper_tooltip';
|
||||
|
||||
|
@ -43,7 +44,9 @@ const UpgradeAvailableVersionStatus: React.FunctionComponent<{
|
|||
}> = React.memo(({ item }) => {
|
||||
const authz = useAuthz();
|
||||
const isDisabled = !authz.integrations.upgradePackages;
|
||||
|
||||
const {
|
||||
actions: { bulkUpgradeIntegrationsWithConfirmModal },
|
||||
} = useInstalledIntegrationsActions();
|
||||
return (
|
||||
<DisabledWrapperTooltip
|
||||
tooltipContent={
|
||||
|
@ -58,8 +61,9 @@ const UpgradeAvailableVersionStatus: React.FunctionComponent<{
|
|||
size="s"
|
||||
iconType="gear"
|
||||
flush="left"
|
||||
// TODO Implement on click https://github.com/elastic/kibana/issues/209867
|
||||
onClick={() => {}}
|
||||
onClick={() => {
|
||||
bulkUpgradeIntegrationsWithConfirmModal([item]);
|
||||
}}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -8,20 +8,14 @@
|
|||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
|
||||
import { useStartServices } from '../../../../../../../hooks';
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
import { useBulkActions } from '../hooks/use_bulk_actions';
|
||||
|
||||
import { ConfirmBulkUpgradeModal } from './confirm_bulk_upgrade_modal';
|
||||
import { ConfirmBulkUninstallModal } from './confirm_bulk_uninstall_modal';
|
||||
import { useInstalledIntegrationsActions } from '../hooks/use_installed_integrations_actions';
|
||||
|
||||
export const InstalledIntegrationsActionMenu: React.FunctionComponent<{
|
||||
selectedItems: InstalledPackageUIPackageListItem[];
|
||||
}> = ({ selectedItems }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const startServices = useStartServices();
|
||||
|
||||
const button = (
|
||||
<EuiButton
|
||||
|
@ -38,40 +32,18 @@ export const InstalledIntegrationsActionMenu: React.FunctionComponent<{
|
|||
);
|
||||
|
||||
const {
|
||||
actions: { bulkUpgradeIntegrations, bulkUninstallIntegrations },
|
||||
} = useBulkActions();
|
||||
actions: { bulkUpgradeIntegrationsWithConfirmModal, bulkUninstallIntegrationsWithConfirmModal },
|
||||
} = useInstalledIntegrationsActions();
|
||||
|
||||
const openUpgradeModal = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
const ref = startServices.overlays.openModal(
|
||||
toMountPoint(
|
||||
<ConfirmBulkUpgradeModal
|
||||
onClose={() => {
|
||||
ref.close();
|
||||
}}
|
||||
onConfirm={({ updatePolicies }) => bulkUpgradeIntegrations(selectedItems, updatePolicies)}
|
||||
selectedItems={selectedItems}
|
||||
/>,
|
||||
startServices
|
||||
)
|
||||
);
|
||||
}, [selectedItems, startServices, bulkUpgradeIntegrations]);
|
||||
return bulkUpgradeIntegrationsWithConfirmModal(selectedItems);
|
||||
}, [selectedItems, bulkUpgradeIntegrationsWithConfirmModal]);
|
||||
|
||||
const openUninstallModal = useCallback(() => {
|
||||
const openUninstallModal = useCallback(async () => {
|
||||
setIsOpen(false);
|
||||
const ref = startServices.overlays.openModal(
|
||||
toMountPoint(
|
||||
<ConfirmBulkUninstallModal
|
||||
onClose={() => {
|
||||
ref.close();
|
||||
}}
|
||||
onConfirm={() => bulkUninstallIntegrations(selectedItems)}
|
||||
selectedItems={selectedItems}
|
||||
/>,
|
||||
startServices
|
||||
)
|
||||
);
|
||||
}, [selectedItems, startServices, bulkUninstallIntegrations]);
|
||||
return bulkUninstallIntegrationsWithConfirmModal(selectedItems);
|
||||
}, [selectedItems, bulkUninstallIntegrationsWithConfirmModal]);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const hasUpgreadableIntegrations = selectedItems.some(
|
||||
|
|
|
@ -17,16 +17,29 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { Action } from '@elastic/eui/src/components/basic_table/action_types';
|
||||
|
||||
import { TableIcon } from '../../../../../../../components/package_icon';
|
||||
import type { PackageListItem } from '../../../../../../../../common';
|
||||
import { type UrlPagination, useLink, useAuthz } from '../../../../../../../hooks';
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
import { useViewPolicies } from '../hooks/use_url_filters';
|
||||
import { useInstalledIntegrationsActions } from '../hooks/use_installed_integrations_actions';
|
||||
|
||||
import { InstallationVersionStatus } from './installation_version_status';
|
||||
import { DisabledWrapperTooltip } from './disabled_wrapper_tooltip';
|
||||
|
||||
function wrapActionWithDisabledTooltip(
|
||||
action: Action<InstalledPackageUIPackageListItem>,
|
||||
disabled: boolean,
|
||||
tooltip: string
|
||||
): Action<InstalledPackageUIPackageListItem> {
|
||||
return {
|
||||
...action,
|
||||
...(disabled ? { enabled: () => false, description: tooltip } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export const InstalledIntegrationsTable: React.FunctionComponent<{
|
||||
installedPackages: InstalledPackageUIPackageListItem[];
|
||||
total: number;
|
||||
|
@ -41,6 +54,9 @@ export const InstalledIntegrationsTable: React.FunctionComponent<{
|
|||
const { getHref } = useLink();
|
||||
const { selectedItems, setSelectedItems } = selection;
|
||||
const { addViewPolicies } = useViewPolicies();
|
||||
const {
|
||||
actions: { bulkUninstallIntegrationsWithConfirmModal, bulkUpgradeIntegrationsWithConfirmModal },
|
||||
} = useInstalledIntegrationsActions();
|
||||
|
||||
const { setPagination } = pagination;
|
||||
const handleTablePagination = React.useCallback(
|
||||
|
@ -94,7 +110,7 @@ export const InstalledIntegrationsTable: React.FunctionComponent<{
|
|||
),
|
||||
render: (item: PackageListItem) => {
|
||||
const url = getHref('integration_details_overview', {
|
||||
pkgkey: `${item.name}-${item.version}`,
|
||||
pkgkey: `${item.name}-${item.installationInfo!.version}`,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -168,33 +184,61 @@ export const InstalledIntegrationsTable: React.FunctionComponent<{
|
|||
// TODO Actions are not yet implemented to be done in https://github.com/elastic/kibana/issues/209867
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.epmInstalledIntegrations.upgradeActionLabel', {
|
||||
defaultMessage: 'Upgrade',
|
||||
}),
|
||||
description: (item) =>
|
||||
i18n.translate('xpack.fleet.epmInstalledIntegrations.upgradeActionDescription', {
|
||||
defaultMessage: 'Upgrade to {version}.',
|
||||
values: { version: item.version },
|
||||
wrapActionWithDisabledTooltip(
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.epmInstalledIntegrations.upgradeActionLabel', {
|
||||
defaultMessage: 'Upgrade',
|
||||
}),
|
||||
icon: 'refresh',
|
||||
type: 'icon',
|
||||
enabled: () => false,
|
||||
},
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.epmInstalledIntegrations.viewPoliciesLabel', {
|
||||
defaultMessage: 'View policies',
|
||||
}),
|
||||
icon: 'search',
|
||||
type: 'icon',
|
||||
description: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.viewPoliciesLabel',
|
||||
description: (item) =>
|
||||
i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.upgradeActionDescription',
|
||||
{
|
||||
defaultMessage: 'Upgrade to {version}.',
|
||||
values: { version: item.version },
|
||||
}
|
||||
),
|
||||
icon: 'refresh',
|
||||
type: 'icon',
|
||||
onClick: (item) => bulkUpgradeIntegrationsWithConfirmModal([item]),
|
||||
enabled: (item) =>
|
||||
item.ui.installation_status === 'upgrade_available' ||
|
||||
item.ui.installation_status === 'upgrade_failed' ||
|
||||
item.ui.installation_status === 'install_failed',
|
||||
},
|
||||
!authz.integrations.upgradePackages,
|
||||
i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.upgradeIntegrationsRequiredPermissionTooltip',
|
||||
{
|
||||
defaultMessage: 'View policies',
|
||||
defaultMessage:
|
||||
"You don't have permissions to upgrade integrations. Contact your administrator.",
|
||||
}
|
||||
),
|
||||
enabled: (item) => (item?.packagePoliciesInfo?.count ?? 0) > 0,
|
||||
},
|
||||
)
|
||||
),
|
||||
wrapActionWithDisabledTooltip(
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.epmInstalledIntegrations.viewPoliciesLabel', {
|
||||
defaultMessage: 'View policies',
|
||||
}),
|
||||
icon: 'search',
|
||||
type: 'icon',
|
||||
description: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.viewPoliciesLabel',
|
||||
{
|
||||
defaultMessage: 'View policies',
|
||||
}
|
||||
),
|
||||
onClick: (item) => addViewPolicies(item.name),
|
||||
enabled: (item) => (item?.packagePoliciesInfo?.count ?? 0) > 0,
|
||||
},
|
||||
!authz.fleet.readAgentPolicies,
|
||||
i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.agentPoliciesRequiredPermissionTooltip',
|
||||
{
|
||||
defaultMessage:
|
||||
"You don't have permissions to view these policies. Contact your administrator.",
|
||||
}
|
||||
)
|
||||
),
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.epmInstalledIntegrations.editIntegrationLabel', {
|
||||
defaultMessage: 'Edit integration',
|
||||
|
@ -207,25 +251,38 @@ export const InstalledIntegrationsTable: React.FunctionComponent<{
|
|||
defaultMessage: 'Edit integration',
|
||||
}
|
||||
),
|
||||
enabled: () => false,
|
||||
href: (item) =>
|
||||
getHref('integration_details_overview', {
|
||||
pkgkey: `${item.name}-${item.installationInfo!.version}`,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.uninstallIntegrationLabel',
|
||||
wrapActionWithDisabledTooltip(
|
||||
{
|
||||
name: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.uninstallIntegrationLabel',
|
||||
{
|
||||
defaultMessage: 'Uninstall integration',
|
||||
}
|
||||
),
|
||||
icon: 'trash',
|
||||
type: 'icon',
|
||||
description: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.uninstallIntegrationLabel',
|
||||
{
|
||||
defaultMessage: 'Uninstall integration',
|
||||
}
|
||||
),
|
||||
onClick: (item) => bulkUninstallIntegrationsWithConfirmModal([item]),
|
||||
},
|
||||
!authz.integrations.removePackages,
|
||||
i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.removeIntegrationsRequiredPermissionTooltip',
|
||||
{
|
||||
defaultMessage: 'Uninstall integration',
|
||||
defaultMessage:
|
||||
"You don't have permissions to remove integrations. Contact your administrator.",
|
||||
}
|
||||
),
|
||||
icon: 'trash',
|
||||
type: 'icon',
|
||||
description: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.uninstallIntegrationLabel',
|
||||
{
|
||||
defaultMessage: 'Uninstall integration',
|
||||
}
|
||||
),
|
||||
enabled: (item) => (item?.packagePoliciesInfo?.count ?? 0) === 0,
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
},
|
||||
]}
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useQueries, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import {
|
||||
sendBulkUninstallPackagesForRq,
|
||||
sendBulkUpgradePackagesForRq,
|
||||
sendGetOneBulkUninstallPackagesForRq,
|
||||
sendGetOneBulkUpgradePackagesForRq,
|
||||
useStartServices,
|
||||
|
@ -145,110 +143,3 @@ export const BulkActionContextProvider: React.FunctionComponent<{ children: Reac
|
|||
</bulkActionsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function useBulkActions() {
|
||||
const {
|
||||
upgradingIntegrations,
|
||||
uninstallingIntegrations,
|
||||
bulkActions: { setPollingBulkActions },
|
||||
} = useContext(bulkActionsContext);
|
||||
const {
|
||||
notifications: { toasts },
|
||||
} = useStartServices();
|
||||
|
||||
const bulkUpgradeIntegrations = useCallback(
|
||||
async (items: InstalledPackageUIPackageListItem[], updatePolicies?: boolean) => {
|
||||
try {
|
||||
const res = await sendBulkUpgradePackagesForRq({
|
||||
packages: items.map((item) => ({ name: item.name })),
|
||||
upgrade_package_policies: updatePolicies,
|
||||
});
|
||||
|
||||
setPollingBulkActions((actions) => [
|
||||
...actions,
|
||||
{
|
||||
taskId: res.taskId,
|
||||
type: 'bulk_upgrade',
|
||||
integrations: items,
|
||||
},
|
||||
]);
|
||||
toasts.addInfo({
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeInProgressTitle',
|
||||
{
|
||||
defaultMessage: 'Upgrade in progress',
|
||||
}
|
||||
),
|
||||
content: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeInProgressDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'The integrations and the policies are upgrading to the latest version.',
|
||||
}
|
||||
),
|
||||
});
|
||||
} catch (error) {
|
||||
toasts.addError(error, {
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Error upgrading integrations',
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
[setPollingBulkActions, toasts]
|
||||
);
|
||||
|
||||
const bulkUninstallIntegrations = useCallback(
|
||||
async (items: InstalledPackageUIPackageListItem[], updatePolicies?: boolean) => {
|
||||
try {
|
||||
const res = await sendBulkUninstallPackagesForRq({
|
||||
packages: items.map((item) => ({
|
||||
name: item.name,
|
||||
version: item.installationInfo!.version,
|
||||
})),
|
||||
});
|
||||
|
||||
setPollingBulkActions((actions) => [
|
||||
...actions,
|
||||
{
|
||||
taskId: res.taskId,
|
||||
type: 'bulk_uninstall',
|
||||
integrations: items,
|
||||
},
|
||||
]);
|
||||
toasts.addInfo({
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUninstallInProgressTitle',
|
||||
{
|
||||
defaultMessage: 'Uninstall in progress',
|
||||
}
|
||||
),
|
||||
});
|
||||
} catch (error) {
|
||||
toasts.addError(error, {
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUninstallErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Error uninstalling integrations',
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
[toasts, setPollingBulkActions]
|
||||
);
|
||||
|
||||
const actions = useMemo(
|
||||
() => ({ bulkUpgradeIntegrations, bulkUninstallIntegrations }),
|
||||
[bulkUpgradeIntegrations, bulkUninstallIntegrations]
|
||||
);
|
||||
|
||||
return {
|
||||
actions,
|
||||
upgradingIntegrations,
|
||||
uninstallingIntegrations,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import {
|
||||
sendRemovePackageForRq,
|
||||
sendBulkUninstallPackagesForRq,
|
||||
sendBulkUpgradePackagesForRq,
|
||||
} from '../../../../../../../hooks/use_request/epm';
|
||||
|
||||
import { createFleetTestRendererMock } from '../../../../../../../mock';
|
||||
|
||||
import { useInstalledIntegrationsActions } from './use_installed_integrations_actions';
|
||||
|
||||
jest.mock('@kbn/react-kibana-mount');
|
||||
jest.mock('../../../../../../../hooks/use_request/epm', () => ({
|
||||
...jest.requireActual('../../../../../../../hooks/use_request/epm'),
|
||||
sendRemovePackageForRq: jest.fn(),
|
||||
sendBulkUninstallPackagesForRq: jest.fn(),
|
||||
sendBulkUpgradePackagesForRq: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useInstalledIntegrationsActions', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(sendRemovePackageForRq).mockReset();
|
||||
jest.mocked(sendBulkUninstallPackagesForRq).mockReset();
|
||||
jest.mocked(sendBulkUpgradePackagesForRq).mockReset();
|
||||
jest.mocked(toMountPoint).mockReset();
|
||||
});
|
||||
describe('bulkUninstallIntegrationsWithConfirmModal', () => {
|
||||
it('should work with single integration', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUninstallIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUninstallIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
modalResult.getByTestId('confirmModalConfirmButton').click();
|
||||
|
||||
await expect(bulkUninstallIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendRemovePackageForRq).toBeCalledTimes(1);
|
||||
expect(sendRemovePackageForRq).toBeCalledWith({ pkgName: 'test', pkgVersion: '1.0.0' });
|
||||
});
|
||||
|
||||
it('should work with multiple integrations', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUninstallIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUninstallIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.1.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
modalResult.getByTestId('confirmModalConfirmButton').click();
|
||||
|
||||
await expect(bulkUninstallIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendBulkUninstallPackagesForRq).toBeCalledTimes(1);
|
||||
expect(sendBulkUninstallPackagesForRq).toBeCalledWith({
|
||||
packages: [
|
||||
{ name: 'test', version: '1.0.0' },
|
||||
{ name: 'test2', version: '1.1.0' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should support canceling action', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUninstallIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUninstallIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
modalResult.getByTestId('confirmModalCancelButton').click();
|
||||
|
||||
await expect(bulkUninstallIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendRemovePackageForRq).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulkUpgradeIntegrationsWithConfirmModal', () => {
|
||||
it('should work with single integration', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUpgradeIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUpgradeIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
modalResult.getByTestId('confirmModalConfirmButton').click();
|
||||
|
||||
await expect(bulkUpgradeIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledTimes(1);
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledWith({
|
||||
packages: [{ name: 'test' }],
|
||||
upgrade_package_policies: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow to upgrade related package policies', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUpgradeIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUpgradeIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
act(() => modalResult.getByTestId('upgradeIntegrationsPoliciesSwitch').click());
|
||||
act(() => modalResult.getByTestId('confirmModalConfirmButton').click());
|
||||
|
||||
await expect(bulkUpgradeIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledTimes(1);
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledWith({
|
||||
packages: [{ name: 'test' }],
|
||||
upgrade_package_policies: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with multiple integrations', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUpgradeIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUpgradeIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.1.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
act(() => modalResult.getByTestId('confirmModalConfirmButton').click());
|
||||
|
||||
await expect(bulkUpgradeIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledTimes(1);
|
||||
expect(sendBulkUpgradePackagesForRq).toBeCalledWith({
|
||||
packages: [{ name: 'test' }, { name: 'test2' }],
|
||||
upgrade_package_policies: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should support cancelling', async () => {
|
||||
const renderer = createFleetTestRendererMock();
|
||||
const res = renderer.renderHook(() => useInstalledIntegrationsActions());
|
||||
const bulkUpgradeIntegrationsWithConfirmModalResult =
|
||||
res.result.current.actions.bulkUpgradeIntegrationsWithConfirmModal([
|
||||
{
|
||||
name: 'test',
|
||||
version: '1.2.0',
|
||||
installationInfo: {
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
] as any);
|
||||
|
||||
// Mount the modal
|
||||
const modal = jest.mocked(toMountPoint).mock.lastCall![0];
|
||||
const modalResult = renderer.render(modal as any);
|
||||
|
||||
modalResult.getByTestId('confirmModalCancelButton').click();
|
||||
|
||||
await expect(bulkUpgradeIntegrationsWithConfirmModalResult).resolves;
|
||||
|
||||
expect(sendBulkUpgradePackagesForRq).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { QueryClientProvider, useQueryClient } from '@tanstack/react-query';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
|
||||
import {
|
||||
sendBulkUninstallPackagesForRq,
|
||||
sendBulkUpgradePackagesForRq,
|
||||
sendRemovePackageForRq,
|
||||
useStartServices,
|
||||
} from '../../../../../../../hooks';
|
||||
import type { InstalledPackageUIPackageListItem } from '../types';
|
||||
import { ConfirmBulkUninstallModal } from '../components/confirm_bulk_uninstall_modal';
|
||||
import { ConfirmBulkUpgradeModal } from '../components/confirm_bulk_upgrade_modal';
|
||||
|
||||
import { bulkActionsContext } from './use_bulk_actions_context';
|
||||
|
||||
export function useInstalledIntegrationsActions() {
|
||||
const {
|
||||
upgradingIntegrations,
|
||||
uninstallingIntegrations,
|
||||
bulkActions: { setPollingBulkActions },
|
||||
} = useContext(bulkActionsContext);
|
||||
const queryClient = useQueryClient();
|
||||
const startServices = useStartServices();
|
||||
const {
|
||||
notifications: { toasts },
|
||||
} = startServices;
|
||||
|
||||
const bulkUpgradeIntegrations = useCallback(
|
||||
async (items: InstalledPackageUIPackageListItem[], updatePolicies?: boolean) => {
|
||||
try {
|
||||
const res = await sendBulkUpgradePackagesForRq({
|
||||
packages: items.map((item) => ({ name: item.name })),
|
||||
upgrade_package_policies: updatePolicies,
|
||||
});
|
||||
|
||||
setPollingBulkActions((actions) => [
|
||||
...actions,
|
||||
{
|
||||
taskId: res.taskId,
|
||||
type: 'bulk_upgrade',
|
||||
integrations: items,
|
||||
},
|
||||
]);
|
||||
toasts.addInfo({
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeInProgressTitle',
|
||||
{
|
||||
defaultMessage: 'Upgrade in progress',
|
||||
}
|
||||
),
|
||||
content: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeInProgressDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'The integrations and the policies are upgrading to the latest version.',
|
||||
}
|
||||
),
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
toasts.addError(error, {
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUpgradeErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Error upgrading integrations',
|
||||
}
|
||||
),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[setPollingBulkActions, toasts]
|
||||
);
|
||||
|
||||
const bulkUninstallIntegrations = useCallback(
|
||||
async (items: InstalledPackageUIPackageListItem[]) => {
|
||||
try {
|
||||
if (items.length === 1) {
|
||||
await sendRemovePackageForRq({
|
||||
pkgName: items[0].name,
|
||||
pkgVersion: items[0].installationInfo!.version,
|
||||
});
|
||||
await queryClient.invalidateQueries(['get-packages']);
|
||||
toasts.addSuccess({
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUninstallSuccessTitleSingle',
|
||||
{
|
||||
defaultMessage: 'Uninstalled {pkgName}',
|
||||
values: { pkgName: items[0].name },
|
||||
}
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const res = await sendBulkUninstallPackagesForRq({
|
||||
packages: items.map((item) => ({
|
||||
name: item.name,
|
||||
version: item.installationInfo!.version,
|
||||
})),
|
||||
});
|
||||
|
||||
setPollingBulkActions((actions) => [
|
||||
...actions,
|
||||
{
|
||||
taskId: res.taskId,
|
||||
type: 'bulk_uninstall',
|
||||
integrations: items,
|
||||
},
|
||||
]);
|
||||
toasts.addInfo({
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUninstallInProgressTitle',
|
||||
{
|
||||
defaultMessage: 'Uninstall in progress',
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
toasts.addError(error, {
|
||||
title: i18n.translate(
|
||||
'xpack.fleet.epmInstalledIntegrations.bulkActions.bulkUninstallErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Error uninstalling integrations',
|
||||
}
|
||||
),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[toasts, queryClient, setPollingBulkActions]
|
||||
);
|
||||
|
||||
const bulkUninstallIntegrationsWithConfirmModal = useCallback(
|
||||
(selectedItems: InstalledPackageUIPackageListItem[]) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const ref = startServices.overlays.openModal(
|
||||
toMountPoint(
|
||||
<ConfirmBulkUninstallModal
|
||||
onClose={() => {
|
||||
ref.close();
|
||||
resolve();
|
||||
}}
|
||||
onConfirm={async () => {
|
||||
// Error handled in bulkUninstallIntegrations
|
||||
const success = await bulkUninstallIntegrations(selectedItems);
|
||||
if (success) {
|
||||
resolve();
|
||||
} else {
|
||||
throw new Error('uninstall integrations failed');
|
||||
}
|
||||
}}
|
||||
selectedItems={selectedItems}
|
||||
/>,
|
||||
startServices
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
[startServices, bulkUninstallIntegrations]
|
||||
);
|
||||
|
||||
const bulkUpgradeIntegrationsWithConfirmModal = useCallback(
|
||||
(selectedItems: InstalledPackageUIPackageListItem[]) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
const ref = startServices.overlays.openModal(
|
||||
toMountPoint(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ConfirmBulkUpgradeModal
|
||||
onClose={() => {
|
||||
ref.close();
|
||||
resolve();
|
||||
}}
|
||||
onConfirm={async ({ updatePolicies }) => {
|
||||
const success = await bulkUpgradeIntegrations(selectedItems, updatePolicies);
|
||||
if (success) {
|
||||
resolve();
|
||||
} else {
|
||||
throw new Error('upgrade integrations failed');
|
||||
}
|
||||
}}
|
||||
selectedItems={selectedItems}
|
||||
/>
|
||||
</QueryClientProvider>,
|
||||
startServices
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
[startServices, queryClient, bulkUpgradeIntegrations]
|
||||
);
|
||||
|
||||
const actions = useMemo(
|
||||
() => ({
|
||||
bulkUpgradeIntegrationsWithConfirmModal,
|
||||
bulkUninstallIntegrationsWithConfirmModal,
|
||||
}),
|
||||
[bulkUpgradeIntegrationsWithConfirmModal, bulkUninstallIntegrationsWithConfirmModal]
|
||||
);
|
||||
|
||||
return {
|
||||
actions,
|
||||
upgradingIntegrations,
|
||||
uninstallingIntegrations,
|
||||
};
|
||||
}
|
|
@ -17,7 +17,8 @@ import { useInstalledIntegrations } from './hooks/use_installed_integrations';
|
|||
import { useUrlFilters, useViewPolicies } from './hooks/use_url_filters';
|
||||
import { InstalledIntegrationsSearchBar } from './components/installed_integrations_search_bar';
|
||||
import type { InstalledPackageUIPackageListItem } from './types';
|
||||
import { BulkActionContextProvider, useBulkActions } from './hooks/use_bulk_actions';
|
||||
import { useInstalledIntegrationsActions } from './hooks/use_installed_integrations_actions';
|
||||
import { BulkActionContextProvider } from './hooks/use_bulk_actions_context';
|
||||
import { PackagePoliciesPanel } from './components/package_policies_panel';
|
||||
|
||||
const ContentWrapper = styled.div`
|
||||
|
@ -31,7 +32,7 @@ const InstalledIntegrationsPageContent: React.FunctionComponent = () => {
|
|||
const filters = useUrlFilters();
|
||||
const { selectedPackageViewPolicies } = useViewPolicies();
|
||||
const pagination = useUrlPagination();
|
||||
const { upgradingIntegrations, uninstallingIntegrations } = useBulkActions();
|
||||
const { upgradingIntegrations, uninstallingIntegrations } = useInstalledIntegrationsActions();
|
||||
const {
|
||||
installedPackages,
|
||||
countPerStatus,
|
||||
|
|
|
@ -9,8 +9,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|||
|
||||
import { useState } from 'react';
|
||||
|
||||
import type { SendRequestResponse } from '@kbn/es-ui-shared-plugin/public';
|
||||
|
||||
import { epmRouteService, isVerificationError } from '../../services';
|
||||
import type {
|
||||
GetCategoriesRequest,
|
||||
|
@ -259,8 +257,8 @@ export const useGetFileByPath = (filePath: string) => {
|
|||
};
|
||||
|
||||
export const useGetFileByPathQuery = (filePath: string) => {
|
||||
return useQuery<SendRequestResponse<string>, RequestError>(['get-file', filePath], () =>
|
||||
sendRequest<string>({
|
||||
return useQuery<string, RequestError>(['get-file', filePath], () =>
|
||||
sendRequestForRq<string>({
|
||||
path: epmRouteService.getFilePath(filePath),
|
||||
method: 'get',
|
||||
version: API_VERSIONS.public.v1,
|
||||
|
@ -343,6 +341,9 @@ export const sendGetOneBulkUninstallPackagesForRq = (taskId: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated use sendRemovePackageForRq instead
|
||||
*/
|
||||
export function sendRemovePackage(
|
||||
{ pkgName, pkgVersion }: DeletePackageRequest['params'],
|
||||
query?: DeletePackageRequest['query']
|
||||
|
@ -355,6 +356,18 @@ export function sendRemovePackage(
|
|||
});
|
||||
}
|
||||
|
||||
export function sendRemovePackageForRq(
|
||||
{ pkgName, pkgVersion }: DeletePackageRequest['params'],
|
||||
query?: DeletePackageRequest['query']
|
||||
) {
|
||||
return sendRequestForRq<DeletePackageResponse>({
|
||||
path: epmRouteService.getRemovePath(pkgName, pkgVersion),
|
||||
method: 'delete',
|
||||
version: API_VERSIONS.public.v1,
|
||||
query,
|
||||
});
|
||||
}
|
||||
|
||||
export const sendRequestReauthorizeTransforms = (
|
||||
pkgName: string,
|
||||
pkgVersion: string,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue