Skip to content

Commit

Permalink
Add ingest pipeline tab to Stack Monitoring
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdover committed Jan 31, 2023
1 parent 4baa14a commit 4957c53
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 4 deletions.
4 changes: 3 additions & 1 deletion x-pack/plugins/monitoring/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"triggersActionsUi",
"alerting",
"actions",
"encryptedSavedObjects"
"encryptedSavedObjects",
"dashboard",
"fleet"
],
"server": true,
"ui": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { includes } from 'lodash';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { FleetStart } from '@kbn/fleet-plugin/public';
import { EuiIcon, EuiToolTip } from '@elastic/eui';
import { PageTemplate } from '../page_template';
import { TabMenuItem, PageTemplateProps } from '../page_template';
import { ML_SUPPORTED_LICENSES } from '../../../../common/constants';
import { ingestPipelineTabOnClick } from './ingest_pipeline_modal';

interface ElasticsearchTemplateProps extends PageTemplateProps {
cluster?: any;
Expand All @@ -19,6 +24,8 @@ export const ElasticsearchTemplate: React.FC<ElasticsearchTemplateProps> = ({
cluster,
...props
}) => {
const { services } = useKibana<{ dashboard?: DashboardStart; fleet?: FleetStart }>();

const tabs: TabMenuItem[] = [
{
id: 'overview',
Expand All @@ -43,6 +50,25 @@ export const ElasticsearchTemplate: React.FC<ElasticsearchTemplateProps> = ({
},
];

if (services.dashboard) {
tabs.push({
id: 'ingest_pipeines',
label: i18n.translate('xpack.monitoring.esNavigation.ingestPipelinesLinkText', {
defaultMessage: 'Ingest Pipelines',
}),
prepend: (
<EuiToolTip
content={i18n.translate('xpack.monitoring.esNavigation.ingestPipelinesBetaTooltip', {
defaultMessage: 'Ingest Pipeline monitoring is a beta feature',
})}
>
<EuiIcon type="beaker" />
</EuiToolTip>
),
onClick: () => ingestPipelineTabOnClick(services),
});
}

if (cluster && mlIsSupported(cluster.license)) {
tabs.push({
id: 'ml',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* 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, { useState } from 'react';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { FleetStart } from '@kbn/fleet-plugin/public';

const INGEST_PIPELINE_DASHBOARD_ID = 'elasticsearch-metrics-ingest-pipelines';

/**
* If the ingest pipeline dashboard is installed, navigate to it. Otherwise, prompt the user to install the package
* first, then navigate. If user does not have permission to install packages, show a message.
* @param services
* @returns
*/
export const ingestPipelineTabOnClick = async (
services: Partial<CoreStart & { dashboard: DashboardStart; fleet: FleetStart }>
) => {
const dashboard = await services.savedObjects!.client.get(
'dashboard',
INGEST_PIPELINE_DASHBOARD_ID
);
const dashboardFound = !dashboard.error && dashboard.attributes;

const navigateToDashboard = () =>
services.dashboard!.locator!.navigate({
dashboardId: INGEST_PIPELINE_DASHBOARD_ID,
});

if (!dashboardFound) {
const installPackage = () =>
services.http!.post('/api/fleet/epm/packages/elasticsearch', {
query: {
prerelease: true,
},
});

const ref = services.overlays!.openModal(
toMountPoint(
<IngestPipelineModal
installPackage={installPackage}
navigateToDashboard={navigateToDashboard}
canInstallPackages={!!services.fleet?.authz.integrations.installPackages}
closeModal={() => ref.close()}
/>,
{
theme$: services.theme?.theme$,
}
)
);

return await ref.onClose;
} else {
return navigateToDashboard();
}
};

/**
* Modal to prompt the user to either install the Elasticsearch integration or contact an admin.
*/
export const IngestPipelineModal = ({
canInstallPackages,
closeModal,
installPackage,
navigateToDashboard,
}: {
closeModal: () => void;
canInstallPackages: boolean;
installPackage: () => Promise<unknown>;
navigateToDashboard: () => void;
}) => {
const [installing, setInstalling] = useState(false);
const [error, setError] = useState<string>();

if (!canInstallPackages) {
return (
<EuiConfirmModal
title={i18n.translate(
'xpack.monitoring.esNavigation.ingestPipelineModal.noPermissionToInstallPackage.packageRequiredTitle',
{ defaultMessage: 'Elasticsearch integration is required' }
)}
confirmButtonText={i18n.translate(
'xpack.monitoring.esNavigation.ingestPipelineModal.noPermissionToInstallPackage.confirmButtonText',
{ defaultMessage: 'OK' }
)}
onCancel={closeModal}
onConfirm={closeModal}
>
<p>
<FormattedMessage
id="xpack.monitoring.esNavigation.ingestPipelineModal.noPermissionToInstallPackage.descriptionText"
defaultMessage="Viewing Ingest pipeline metrics requires installing the Elasticsearch integration. You must ask your administrator to install it."
/>
</p>
</EuiConfirmModal>
);
}

return (
<EuiConfirmModal
title={i18n.translate(
'xpack.monitoring.esNavigation.ingestPipelineModal.installPromptTitle',
{
defaultMessage: 'Install Elasticsearch integration?',
}
)}
confirmButtonText={i18n.translate(
'xpack.monitoring.esNavigation.ingestPipelineModal.installButtonText',
{ defaultMessage: 'Install' }
)}
cancelButtonText={i18n.translate(
'xpack.monitoring.esNavigation.ingestPipelineModal.cancelButtonText',
{ defaultMessage: 'Cancel' }
)}
confirmButtonDisabled={installing}
onCancel={closeModal}
onConfirm={async () => {
setInstalling(true);
try {
await installPackage();
closeModal();
navigateToDashboard();
} catch (e) {
setError(e.body?.error || e.message);
}
}}
>
{error && (
<>
<EuiCallOut
title={
<FormattedMessage
id="xpack.monitoring.esNavigation.ingestPipelineModal.errorCalloutText"
defaultMessage="Could not install the package due to an error: {error}"
values={{ error }}
/>
}
color="danger"
iconType="alert"
/>
<EuiSpacer />
</>
)}
<p>
<FormattedMessage
id="xpack.monitoring.esNavigation.ingestPipelineModal.installPromptDescriptionText"
defaultMessage="Viewing Ingest pipeline metrics requires installing the Elasticsearch integration. Do you
want to install it now?"
/>
</p>
</EuiConfirmModal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export interface TabMenuItem {
id: string;
label: string;
testSubj?: string;
route: string;
route?: string;
onClick?: () => void;
prepend?: React.ReactNode;
}
export interface PageTemplateProps {
title: string;
Expand Down Expand Up @@ -139,8 +141,10 @@ export const PageTemplate: React.FC<PageTemplateProps> = ({
disabled={isDisabledTab(product)}
title={item.label}
data-test-subj={item.testSubj}
href={createHref(item.route)}
isSelected={isTabSelected(item.route)}
href={item.route ? createHref(item.route) : undefined}
isSelected={item.route ? isTabSelected(item.route) : undefined}
onClick={item.onClick}
prepend={item.prepend}
>
{item.label}
</EuiTab>
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/monitoring/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
export type { MonitoringConfig } from '../server';
export type { MLJobs } from '../server/lib/elasticsearch/get_ml_jobs';
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { FleetStart } from '@kbn/fleet-plugin/public';

export interface MonitoringStartPluginDependencies {
navigation: NavigationStart;
data: DataPublicPluginStart;
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
usageCollection: UsageCollectionSetup;
dataViews: DataViewsPublicPluginStart;
dashboard?: DashboardStart;
fleet?: FleetStart;
}

interface LegacyStartDependencies {
Expand Down

0 comments on commit 4957c53

Please sign in to comment.