mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
123580 o11 rules page (#124132)
* testing find rules api & load observability rules * add rules option in observability sidebar * make rules menu option configurable * create o11y rules page * update manage rules link * rules page * filter o11y rule types only(temp solution) * remove unused stuff * Add documentation link * fix typescript errors * add selection to EuiBasicTable * add rest columns in the table * toggle popover * add actions column * temp * add breadcrumbs to rules page * add pagination to rules page * add onChange handler in rules pagination * add create rule button * add icon type to the create rule button * Show number of rules * add auto refresh button * use correct rule management link in apm based on feature flag * use correct rule management link in infra and observability alerts page based on on feature flag * centralize useRulesLink logic inside the new useRulesLinkCreator observability hook * useRulesLink in uptime * useRulesLink in apm * mock observability useLinks function in uptime tests * temporarily remove the create rule button * remove unused console statement * remove unused button * fix uptime failing tests * remove useContextForPlugin and rename hook to create_use_rules_link * remove useKibanaForContext from uptime and use useKibana instead * remove unused imports * add a todo comment in the loadRules export * use await import for createUseRulesLink and declare core and setup as async * fix typescript error * Revert "fix typescript error" This reverts commitc5a67d5d56
. * Revert "use await import for createUseRulesLink and declare core and setup as async" This reverts commit627a6265cf
. * experiment with page bundle size * fix for useEffect * use async import for loadRules * experiments * Revert "experiments" This reverts commit8b389dbf6a
. * increase page bundle size limit Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
b5e194532d
commit
2fa485a29b
23 changed files with 357 additions and 45 deletions
|
@ -41,7 +41,7 @@ pageLoadAssetSize:
|
|||
monitoring: 80000
|
||||
navigation: 37269
|
||||
newsfeed: 42228
|
||||
observability: 89709
|
||||
observability: 95000
|
||||
painlessLab: 179748
|
||||
remoteClusters: 51327
|
||||
rollup: 97204
|
||||
|
|
|
@ -16,6 +16,7 @@ import React, { useState } from 'react';
|
|||
import { IBasePath } from '../../../../../../../src/core/public';
|
||||
import { AlertType } from '../../../../common/alert_types';
|
||||
import { AlertingFlyout } from '../../alerting/alerting_flyout';
|
||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||
|
||||
const alertLabel = i18n.translate('xpack.apm.home.alertsMenu.alerts', {
|
||||
defaultMessage: 'Alerts and rules',
|
||||
|
@ -63,7 +64,9 @@ export function AlertingPopoverAndFlyout({
|
|||
}: Props) {
|
||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||
const [alertType, setAlertType] = useState<AlertType | null>(null);
|
||||
|
||||
const {
|
||||
plugins: { observability },
|
||||
} = useApmPluginContext();
|
||||
const button = (
|
||||
<EuiHeaderLink
|
||||
color="text"
|
||||
|
@ -103,9 +106,7 @@ export function AlertingPopoverAndFlyout({
|
|||
'xpack.apm.home.alertsMenu.viewActiveAlerts',
|
||||
{ defaultMessage: 'Manage rules' }
|
||||
),
|
||||
href: basePath.prepend(
|
||||
'/app/management/insightsAndAlerting/triggersActions/alerts'
|
||||
),
|
||||
href: observability.useRulesLink().href,
|
||||
icon: 'tableOfContents',
|
||||
},
|
||||
]
|
||||
|
|
|
@ -17,14 +17,17 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { PrefilledInventoryAlertFlyout } from '../../inventory/components/alert_flyout';
|
||||
import { PrefilledThresholdAlertFlyout } from '../../metric_threshold/components/alert_flyout';
|
||||
import { useRulesLink } from '../../../../../observability/public';
|
||||
import { InfraClientStartDeps } from '../../../types';
|
||||
|
||||
type VisibleFlyoutType = 'inventory' | 'threshold' | null;
|
||||
|
||||
export const MetricsAlertDropdown = () => {
|
||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||
const [visibleFlyoutType, setVisibleFlyoutType] = useState<VisibleFlyoutType>(null);
|
||||
const uiCapabilities = useKibana().services.application?.capabilities;
|
||||
|
||||
const {
|
||||
services: { observability },
|
||||
} = useKibana<InfraClientStartDeps>();
|
||||
const canCreateAlerts = useMemo(
|
||||
() => Boolean(uiCapabilities?.infrastructure?.save),
|
||||
[uiCapabilities]
|
||||
|
@ -83,7 +86,7 @@ export const MetricsAlertDropdown = () => {
|
|||
[setVisibleFlyoutType, closePopover]
|
||||
);
|
||||
|
||||
const manageRulesLinkProps = useRulesLink();
|
||||
const manageRulesLinkProps = observability.useRulesLink();
|
||||
|
||||
const manageAlertsMenuItem = useMemo(
|
||||
() => ({
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
import { EuiContextMenuItem } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useRulesLink } from '../../../../../observability/public';
|
||||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { InfraClientStartDeps } from '../../../types';
|
||||
|
||||
export const ManageAlertsContextMenuItem = () => {
|
||||
const manageRulesLinkProps = useRulesLink();
|
||||
const {
|
||||
services: { observability },
|
||||
} = useKibana<InfraClientStartDeps>();
|
||||
const manageRulesLinkProps = observability.useRulesLink();
|
||||
return (
|
||||
<EuiContextMenuItem icon="tableOfContents" key="manageLink" {...manageRulesLinkProps}>
|
||||
<FormattedMessage id="xpack.infra.alerting.manageAlerts" defaultMessage="Manage rules" />
|
||||
|
|
|
@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n';
|
|||
import { EuiPopover, EuiContextMenuItem, EuiContextMenuPanel, EuiHeaderLink } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { AlertFlyout } from './alert_flyout';
|
||||
import { useRulesLink } from '../../../../../observability/public';
|
||||
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
|
||||
|
||||
const readOnlyUserTooltipContent = i18n.translate(
|
||||
|
@ -31,13 +30,14 @@ export const AlertDropdown = () => {
|
|||
const {
|
||||
services: {
|
||||
application: { capabilities },
|
||||
observability,
|
||||
},
|
||||
} = useKibanaContextForPlugin();
|
||||
const canCreateAlerts = capabilities?.logs?.save ?? false;
|
||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||
const [flyoutVisible, setFlyoutVisible] = useState(false);
|
||||
|
||||
const manageRulesLinkProps = useRulesLink({
|
||||
const manageRulesLinkProps = observability.useRulesLink({
|
||||
hrefOnly: true,
|
||||
});
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ describe('renderApp', () => {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ describe('APMSection', () => {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
},
|
||||
observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(),
|
||||
|
|
|
@ -47,6 +47,7 @@ describe('UXSection', () => {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 { Options, useLinkProps } from './use_link_props';
|
||||
|
||||
export function createUseRulesLink(isNewRuleManagementEnabled = false) {
|
||||
return function (options: Options = {}) {
|
||||
const linkProps = isNewRuleManagementEnabled
|
||||
? {
|
||||
app: 'observability',
|
||||
pathname: '/rules',
|
||||
}
|
||||
: {
|
||||
app: 'management',
|
||||
pathname: '/insightsAndAlerting/triggersActions/alerts',
|
||||
};
|
||||
return useLinkProps(linkProps, options);
|
||||
};
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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 { useLinkProps, Options, LinkProps } from './use_link_props';
|
||||
|
||||
export function useRulesLink(options?: Options): LinkProps {
|
||||
const manageRulesLinkProps = useLinkProps(
|
||||
{
|
||||
app: 'management',
|
||||
pathname: '/insightsAndAlerting/triggersActions/alerts',
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
return manageRulesLinkProps;
|
||||
}
|
|
@ -29,6 +29,7 @@ describe('useTimeRange', () => {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
|
@ -78,6 +79,7 @@ describe('useTimeRange', () => {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
|
|
|
@ -34,6 +34,7 @@ export { uptimeOverviewLocatorID } from '../common';
|
|||
export interface ConfigSchema {
|
||||
unsafe: {
|
||||
alertingExperience: { enabled: boolean };
|
||||
rules: { enabled: boolean };
|
||||
cases: { enabled: boolean };
|
||||
overviewNext: { enabled: boolean };
|
||||
};
|
||||
|
@ -82,7 +83,7 @@ export * from './typings';
|
|||
export { useChartTheme } from './hooks/use_chart_theme';
|
||||
export { useBreadcrumbs } from './hooks/use_breadcrumbs';
|
||||
export { useTheme } from './hooks/use_theme';
|
||||
export { useRulesLink } from './hooks/use_rules_link';
|
||||
export { createUseRulesLink } from './hooks/create_use_rules_link';
|
||||
export { useLinkProps, shouldHandleLinkEvent } from './hooks/use_link_props';
|
||||
export type { LinkDescriptor } from './hooks/use_link_props';
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ interface RuleStatsState {
|
|||
muted: number;
|
||||
error: number;
|
||||
}
|
||||
|
||||
export interface TopAlert {
|
||||
fields: ParsedTechnicalFields & ParsedExperimentalFields;
|
||||
start: number;
|
||||
|
@ -69,7 +70,7 @@ const ALERT_STATUS_REGEX = new RegExp(
|
|||
);
|
||||
|
||||
function AlertsPage() {
|
||||
const { core, plugins, ObservabilityPageTemplate } = usePluginContext();
|
||||
const { core, plugins, ObservabilityPageTemplate, config } = usePluginContext();
|
||||
const [alertFilterStatus, setAlertFilterStatus] = useState('' as AlertStatusFilterButton);
|
||||
const { prepend } = core.http.basePath;
|
||||
const refetch = useRef<() => void>();
|
||||
|
@ -137,9 +138,9 @@ function AlertsPage() {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// In a future milestone we'll have a page dedicated to rule management in
|
||||
// observability. For now link to the settings page.
|
||||
const manageRulesHref = prepend('/app/management/insightsAndAlerting/triggersActions/alerts');
|
||||
const manageRulesHref = config.unsafe.rules
|
||||
? prepend('/app/observability/rules')
|
||||
: prepend('/insightsAndAlerting/triggersActions/alerts');
|
||||
|
||||
const dynamicIndexPatternsAsyncState = useAsync(async (): Promise<DataViewBase[]> => {
|
||||
if (indexNames.length === 0) {
|
||||
|
|
|
@ -80,6 +80,7 @@ const withCore = makeDecorator({
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
},
|
||||
core: options as CoreStart,
|
||||
|
|
261
x-pack/plugins/observability/public/pages/rules/index.tsx
Normal file
261
x-pack/plugins/observability/public/pages/rules/index.tsx
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* 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, useEffect, useCallback } from 'react';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
EuiBasicTable,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButtonEmpty,
|
||||
EuiText,
|
||||
EuiBadge,
|
||||
EuiPopover,
|
||||
EuiContextMenuPanel,
|
||||
EuiContextMenuItem,
|
||||
EuiHorizontalRule,
|
||||
EuiAutoRefreshButton,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
||||
|
||||
import { useKibana } from '../../utils/kibana_react';
|
||||
|
||||
const DEFAULT_SEARCH_PAGE_SIZE: number = 25;
|
||||
|
||||
interface RuleState {
|
||||
data: [];
|
||||
totalItemsCount: number;
|
||||
}
|
||||
|
||||
interface Pagination {
|
||||
index: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export function RulesPage() {
|
||||
const { core, ObservabilityPageTemplate } = usePluginContext();
|
||||
const { docLinks } = useKibana().services;
|
||||
const {
|
||||
http,
|
||||
notifications: { toasts },
|
||||
} = core;
|
||||
const [rules, setRules] = useState<RuleState>({ data: [], totalItemsCount: 0 });
|
||||
const [page, setPage] = useState<Pagination>({ index: 0, size: DEFAULT_SEARCH_PAGE_SIZE });
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
||||
async function loadObservabilityRules() {
|
||||
const { loadRules } = await import('../../../../triggers_actions_ui/public');
|
||||
try {
|
||||
const response = await loadRules({
|
||||
http,
|
||||
page: { index: 0, size: DEFAULT_SEARCH_PAGE_SIZE },
|
||||
typesFilter: [
|
||||
'xpack.uptime.alerts.monitorStatus',
|
||||
'xpack.uptime.alerts.tls',
|
||||
'xpack.uptime.alerts.tlsCertificate',
|
||||
'xpack.uptime.alerts.durationAnomaly',
|
||||
'apm.error_rate',
|
||||
'apm.transaction_error_rate',
|
||||
'apm.transaction_duration',
|
||||
'apm.transaction_duration_anomaly',
|
||||
'metrics.alert.inventory.threshold',
|
||||
'metrics.alert.threshold',
|
||||
'logs.alert.document.count',
|
||||
],
|
||||
});
|
||||
setRules({
|
||||
data: response.data as any,
|
||||
totalItemsCount: response.total,
|
||||
});
|
||||
} catch (_e) {
|
||||
toasts.addDanger({
|
||||
title: i18n.translate('xpack.observability.rules.loadError', {
|
||||
defaultMessage: 'Unable to load rules',
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum RuleStatus {
|
||||
enabled = 'enabled',
|
||||
disabled = 'disabled',
|
||||
}
|
||||
|
||||
const statuses = Object.values(RuleStatus);
|
||||
const togglePopover = useCallback(() => setIsPopoverOpen(!isPopoverOpen), [isPopoverOpen]);
|
||||
const popOverButton = (
|
||||
<EuiBadge
|
||||
iconType="arrowDown"
|
||||
iconSide="right"
|
||||
onClick={togglePopover}
|
||||
onClickAriaLabel="Change status"
|
||||
>
|
||||
Enabled
|
||||
</EuiBadge>
|
||||
);
|
||||
|
||||
const panelItems = statuses.map((status) => (
|
||||
<EuiContextMenuItem>
|
||||
<EuiBadge>{status}</EuiBadge>
|
||||
</EuiContextMenuItem>
|
||||
));
|
||||
|
||||
useEffect(() => {
|
||||
loadObservabilityRules();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', {
|
||||
defaultMessage: 'Rules',
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
const rulesTableColumns = [
|
||||
{
|
||||
field: 'name',
|
||||
name: i18n.translate('xpack.observability.rules.rulesTable.columns.nameTitle', {
|
||||
defaultMessage: 'Rule Name',
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'executionStatus.lastExecutionDate',
|
||||
name: i18n.translate('xpack.observability.rules.rulesTable.columns.lastRunTitle', {
|
||||
defaultMessage: 'Last run',
|
||||
}),
|
||||
render: (date: Date) => {
|
||||
if (date) {
|
||||
return (
|
||||
<>
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText color="subdued" size="xs">
|
||||
{moment(date).fromNow()}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'executionStatus.status',
|
||||
name: i18n.translate('xpack.observability.rules.rulesTable.columns.lastResponseTitle', {
|
||||
defaultMessage: 'Last response',
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'enabled',
|
||||
name: i18n.translate('xpack.observability.rules.rulesTable.columns.statusTitle', {
|
||||
defaultMessage: 'Status',
|
||||
}),
|
||||
render: (_enabled: boolean) => {
|
||||
return (
|
||||
<EuiPopover
|
||||
button={popOverButton}
|
||||
anchorPosition="downLeft"
|
||||
isOpen={isPopoverOpen}
|
||||
panelPaddingSize="none"
|
||||
>
|
||||
<EuiContextMenuPanel items={panelItems} />
|
||||
</EuiPopover>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: '*',
|
||||
name: i18n.translate('xpack.observability.rules.rulesTable.columns.actionsTitle', {
|
||||
defaultMessage: 'Actions',
|
||||
}),
|
||||
actions: [
|
||||
{
|
||||
name: 'Edit',
|
||||
isPrimary: true,
|
||||
description: 'Edit this rule',
|
||||
icon: 'pencil',
|
||||
type: 'icon',
|
||||
onClick: () => {},
|
||||
'data-test-subj': 'action-edit',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<ObservabilityPageTemplate
|
||||
pageHeader={{
|
||||
pageTitle: (
|
||||
<>{i18n.translate('xpack.observability.rulesTitle', { defaultMessage: 'Rules' })} </>
|
||||
),
|
||||
rightSideItems: [
|
||||
<EuiButtonEmpty
|
||||
href={docLinks.links.alerting.guide}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
data-test-subj="documentationLink"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.observability.rules.docsLinkText"
|
||||
defaultMessage="Documentation"
|
||||
/>
|
||||
</EuiButtonEmpty>,
|
||||
],
|
||||
}}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s" color="subdued" data-test-subj="totalAlertsCount">
|
||||
<FormattedMessage
|
||||
id="xpack.observability.rules.totalItemsCountDescription"
|
||||
defaultMessage="Showing: {pageSize} of {totalItemCount} Rules"
|
||||
values={{
|
||||
totalItemCount: rules.totalItemsCount,
|
||||
pageSize: rules.data.length,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiAutoRefreshButton
|
||||
isPaused={false}
|
||||
refreshInterval={3000}
|
||||
onRefreshChange={() => {}}
|
||||
shortHand
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiHorizontalRule margin="xs" />
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiBasicTable
|
||||
items={rules.data}
|
||||
hasActions={true}
|
||||
columns={rulesTableColumns}
|
||||
isSelectable={true}
|
||||
pagination={{
|
||||
pageIndex: page.index,
|
||||
pageSize: page.size,
|
||||
totalItemCount: rules.totalItemsCount,
|
||||
}}
|
||||
onChange={({ page: changedPage }: { page: Pagination }) => {
|
||||
setPage(changedPage);
|
||||
}}
|
||||
selection={{
|
||||
selectable: () => true,
|
||||
onSelectionChange: (selectedItems) => {},
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</ObservabilityPageTemplate>
|
||||
);
|
||||
}
|
|
@ -46,6 +46,7 @@ import { createNavigationRegistry, NavigationEntry } from './services/navigation
|
|||
import { updateGlobalNavigation } from './update_global_navigation';
|
||||
import { getExploratoryViewEmbeddable } from './components/shared/exploratory_view/embeddable';
|
||||
import { createExploratoryViewUrl } from './components/shared/exploratory_view/configurations/utils';
|
||||
import { createUseRulesLink } from './hooks/create_use_rules_link';
|
||||
|
||||
export type ObservabilityPublicSetup = ReturnType<Plugin['setup']>;
|
||||
|
||||
|
@ -92,11 +93,20 @@ export class Plugin
|
|||
path: '/alerts',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
},
|
||||
{
|
||||
id: 'rules',
|
||||
title: i18n.translate('xpack.observability.rulesLinkTitle', {
|
||||
defaultMessage: 'Rules',
|
||||
}),
|
||||
order: 8002,
|
||||
path: '/rules',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
},
|
||||
getCasesDeepLinks({
|
||||
basePath: casesPath,
|
||||
extend: {
|
||||
[CasesDeepLinkId.cases]: {
|
||||
order: 8002,
|
||||
order: 8003,
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
},
|
||||
[CasesDeepLinkId.casesCreate]: {
|
||||
|
@ -242,6 +252,7 @@ export class Plugin
|
|||
navigation: {
|
||||
registerSections: this.navigationRegistry.registerSections,
|
||||
},
|
||||
useRulesLink: createUseRulesLink(config.unsafe.rules.enabled),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -270,6 +281,7 @@ export class Plugin
|
|||
},
|
||||
createExploratoryViewUrl,
|
||||
ExploratoryViewEmbeddable: getExploratoryViewEmbeddable(coreStart, pluginsStart),
|
||||
useRulesLink: createUseRulesLink(config.unsafe.rules.enabled),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { LandingPage } from '../pages/landing';
|
|||
import { OverviewPage } from '../pages/overview';
|
||||
import { jsonRt } from './json_rt';
|
||||
import { ObservabilityExploratoryView } from '../components/shared/exploratory_view/obsv_exploratory_view';
|
||||
import { RulesPage } from '../pages/rules';
|
||||
|
||||
export type RouteParams<T extends keyof typeof routes> = DecodeParams<typeof routes[T]['params']>;
|
||||
|
||||
|
@ -87,4 +88,11 @@ export const routes = {
|
|||
},
|
||||
exact: true,
|
||||
},
|
||||
'/rules': {
|
||||
handler: () => {
|
||||
return <RulesPage />;
|
||||
},
|
||||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -48,6 +48,14 @@ export function updateGlobalNavigation({
|
|||
? AppNavLinkStatus.visible
|
||||
: AppNavLinkStatus.hidden,
|
||||
};
|
||||
case 'rules':
|
||||
return {
|
||||
...link,
|
||||
navLinkStatus:
|
||||
config.unsafe.rules.enabled && someVisible
|
||||
? AppNavLinkStatus.visible
|
||||
: AppNavLinkStatus.hidden,
|
||||
};
|
||||
default:
|
||||
return link;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ const config = {
|
|||
alertingExperience: { enabled: true },
|
||||
cases: { enabled: true },
|
||||
overviewNext: { enabled: false },
|
||||
rules: { enabled: false },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ export const config: PluginConfigDescriptor = {
|
|||
}),
|
||||
unsafe: schema.object({
|
||||
alertingExperience: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
||||
rules: schema.object({ enabled: schema.boolean({ defaultValue: false }) }),
|
||||
cases: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
||||
overviewNext: schema.object({ enabled: schema.boolean({ defaultValue: false }) }),
|
||||
}),
|
||||
|
|
|
@ -45,6 +45,8 @@ export function plugin() {
|
|||
|
||||
export { Plugin };
|
||||
export * from './plugin';
|
||||
// TODO remove this import when we expose the Rules tables as a component
|
||||
export { loadRules } from './application/lib/rule_api/rules';
|
||||
export { loadRuleAggregations } from './application/lib/rule_api/aggregate';
|
||||
|
||||
export { loadActionTypes } from './application/lib/action_connector_api/connector_types';
|
||||
|
|
|
@ -18,6 +18,8 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { CLIENT_ALERT_TYPES } from '../../../../common/constants/alerts';
|
||||
import { ClientPluginsStart } from '../../../../public/apps/plugin';
|
||||
|
||||
import { ToggleFlyoutTranslations } from './translations';
|
||||
import { ToggleAlertFlyoutButtonProps } from './alerts_containers';
|
||||
|
||||
|
@ -43,7 +45,10 @@ export const ToggleAlertFlyoutButtonComponent: React.FC<Props> = ({
|
|||
}) => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const kibana = useKibana();
|
||||
|
||||
const {
|
||||
services: { observability },
|
||||
} = useKibana<ClientPluginsStart>();
|
||||
const manageRulesUrl = observability.useRulesLink();
|
||||
const hasUptimeWrite = kibana.services.application?.capabilities.uptime?.save ?? false;
|
||||
|
||||
const monitorStatusAlertContextMenuItem: EuiContextMenuPanelItemDescriptor = {
|
||||
|
@ -70,12 +75,7 @@ export const ToggleAlertFlyoutButtonComponent: React.FC<Props> = ({
|
|||
'aria-label': ToggleFlyoutTranslations.navigateToAlertingUIAriaLabel,
|
||||
'data-test-subj': 'xpack.uptime.navigateToAlertingUi',
|
||||
name: (
|
||||
<EuiLink
|
||||
color="text"
|
||||
href={kibana.services?.application?.getUrlForApp(
|
||||
'management/insightsAndAlerting/triggersActions/alerts'
|
||||
)}
|
||||
>
|
||||
<EuiLink color="text" href={manageRulesUrl.href}>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.navigateToAlertingButton.content"
|
||||
defaultMessage="Manage rules"
|
||||
|
|
|
@ -134,6 +134,7 @@ export const mockCore: () => Partial<CoreStart> = () => {
|
|||
storage: createMockStore(),
|
||||
data: dataPluginMock.createStartContract(),
|
||||
observability: {
|
||||
useRulesLink: () => ({ href: 'newRuleLink' }),
|
||||
navigation: {
|
||||
// @ts-ignore
|
||||
PageTemplate: EuiPageTemplate,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue