diff --git a/x-pack/plugins/observability/public/pages/rule_details/index.tsx b/x-pack/plugins/observability/public/pages/rule_details/index.tsx index 59b81ff615df2..27ed9671a0a15 100644 --- a/x-pack/plugins/observability/public/pages/rule_details/index.tsx +++ b/x-pack/plugins/observability/public/pages/rule_details/index.tsx @@ -58,16 +58,15 @@ import { RuleDetailsPathParams, TabId } from './types'; import { useBreadcrumbs } from '../../hooks/use_breadcrumbs'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useFetchRule } from '../../hooks/use_fetch_rule'; -import { RULES_BREADCRUMB_TEXT } from '../rules/translations'; import { PageTitle } from './components'; import { getHealthColor } from './config'; import { hasExecuteActionsCapability, hasAllPrivilege } from './config'; import { paths } from '../../config/paths'; import { ALERT_STATUS_ALL } from '../../../common/constants'; -import { AlertStatus } from '../../../common/typings'; import { observabilityFeatureId, ruleDetailsLocatorID } from '../../../common'; import { ALERT_STATUS_LICENSE_ERROR, rulesStatusesTranslationsMapping } from './translations'; -import { ObservabilityAppServices } from '../../application/types'; +import type { AlertStatus } from '../../../common/typings'; +import type { ObservabilityAppServices } from '../../application/types'; export function RuleDetailsPage() { const { @@ -219,7 +218,9 @@ export function RuleDetailsPage() { }, { href: http.basePath.prepend(paths.observability.rules), - text: RULES_BREADCRUMB_TEXT, + text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { + defaultMessage: 'Rules', + }), }, { text: rule && rule.name, diff --git a/x-pack/plugins/observability/public/pages/rules/config.ts b/x-pack/plugins/observability/public/pages/rules/config.ts deleted file mode 100644 index 4a87792c3c602..0000000000000 --- a/x-pack/plugins/observability/public/pages/rules/config.ts +++ /dev/null @@ -1,15 +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 { Rule, RuleType } from '@kbn/triggers-actions-ui-plugin/public'; - -export type InitialRule = Partial & - Pick; - -export function hasAllPrivilege(rule: InitialRule, ruleType?: RuleType): boolean { - return ruleType?.authorizedConsumers[rule.consumer]?.all ?? false; -} diff --git a/x-pack/plugins/observability/public/pages/rules/index.test.tsx b/x-pack/plugins/observability/public/pages/rules/rules.test.tsx similarity index 99% rename from x-pack/plugins/observability/public/pages/rules/index.test.tsx rename to x-pack/plugins/observability/public/pages/rules/rules.test.tsx index 0fc0937c89193..1c0aeb3010a7c 100644 --- a/x-pack/plugins/observability/public/pages/rules/index.test.tsx +++ b/x-pack/plugins/observability/public/pages/rules/rules.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { CoreStart } from '@kbn/core/public'; import { ObservabilityPublicPluginsStart } from '../../plugin'; -import { RulesPage } from '.'; +import { RulesPage } from './rules'; import { kibanaStartMock } from '../../utils/kibana_react.mock'; import * as pluginContext from '../../hooks/use_plugin_context'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; diff --git a/x-pack/plugins/observability/public/pages/rules/index.tsx b/x-pack/plugins/observability/public/pages/rules/rules.tsx similarity index 62% rename from x-pack/plugins/observability/public/pages/rules/index.tsx rename to x-pack/plugins/observability/public/pages/rules/rules.tsx index 1da2506ac4b51..181ada030594b 100644 --- a/x-pack/plugins/observability/public/pages/rules/index.tsx +++ b/x-pack/plugins/observability/public/pages/rules/rules.tsx @@ -6,31 +6,20 @@ */ import React, { useState } from 'react'; +import { useHistory } from 'react-router-dom'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useLoadRuleTypes } from '@kbn/triggers-actions-ui-plugin/public'; +import { RuleStatus, useLoadRuleTypes } from '@kbn/triggers-actions-ui-plugin/public'; import { ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common'; -import type { RulesListVisibleColumns } from '@kbn/triggers-actions-ui-plugin/public'; +import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { Provider, rulesPageStateContainer, useRulesPageStateContainer } from './state_container'; import { useKibana } from '../../utils/kibana_react'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useBreadcrumbs } from '../../hooks/use_breadcrumbs'; import { useGetFilteredRuleTypes } from '../../hooks/use_get_filtered_rule_types'; -import { RULES_PAGE_TITLE, RULES_BREADCRUMB_TEXT } from './translations'; -const RULES_LIST_COLUMNS_KEY = 'observability_rulesListColumns'; -const RULES_LIST_COLUMNS: RulesListVisibleColumns[] = [ - 'ruleName', - 'ruleExecutionStatusLastDate', - 'ruleSnoozeNotify', - 'ruleExecutionStatus', - 'ruleExecutionState', -]; - -function RulesPage() { - const { ObservabilityPageTemplate } = usePluginContext(); +export function RulesPage() { const { http, docLinks, @@ -40,23 +29,36 @@ function RulesPage() { getRulesSettingsLink: RulesSettingsLink, }, } = useKibana().services; - - const { status, setStatus, lastResponse, setLastResponse } = useRulesPageStateContainer(); + const { ObservabilityPageTemplate } = usePluginContext(); + const history = useHistory(); const filteredRuleTypes = useGetFilteredRuleTypes(); const { ruleTypes } = useLoadRuleTypes({ filteredRuleTypes, }); - const [addRuleFlyoutVisibility, setAddRuleFlyoutVisibility] = useState(false); - const [refresh, setRefresh] = useState(new Date()); - const authorizedRuleTypes = [...ruleTypes.values()]; - const authorizedToCreateAnyRules = authorizedRuleTypes.some( (ruleType) => ruleType.authorizedConsumers[ALERTS_FEATURE_ID]?.all ); + const urlStateStorage = createKbnUrlStateStorage({ + history, + useHash: false, + useHashQuery: false, + }); + + const { status, lastResponse } = urlStateStorage.get<{ + status: RuleStatus[]; + lastResponse: string[]; + }>('_a') || { status: [], lastResponse: [] }; + + const [stateStatus, setStatus] = useState(status); + const [stateLastResponse, setLastResponse] = useState(lastResponse); + const [stateRefresh, setRefresh] = useState(new Date()); + + const [addRuleFlyoutVisibility, setAddRuleFlyoutVisibility] = useState(false); + useBreadcrumbs([ { text: i18n.translate('xpack.observability.breadcrumbs.alertsLinkText', { @@ -65,21 +67,38 @@ function RulesPage() { href: http.basePath.prepend('/app/observability/alerts'), }, { - text: RULES_BREADCRUMB_TEXT, + text: i18n.translate('xpack.observability.breadcrumbs.rulesLinkText', { + defaultMessage: 'Rules', + }), }, ]); + const handleStatusFilterChange = (newStatus: RuleStatus[]) => { + setStatus(newStatus); + urlStateStorage.set('_a', { status: newStatus, lastResponse }); + return { lastResponse: stateLastResponse || [], status: newStatus }; + }; + + const handleLastRunOutcomeFilterChange = (newLastResponse: string[]) => { + setRefresh(new Date()); + setLastResponse(newLastResponse); + urlStateStorage.set('_a', { status, lastResponse: newLastResponse }); + return { lastResponse: newLastResponse, status: stateStatus || [] }; + }; + return ( {RULES_PAGE_TITLE}, + pageTitle: i18n.translate('xpack.observability.rulesTitle', { + defaultMessage: 'Rules', + }), rightSideItems: [ setAddRuleFlyoutVisibility(true)} > , , @@ -136,13 +161,3 @@ function RulesPage() { ); } - -function WrappedRulesPage() { - return ( - - - - ); -} - -export { WrappedRulesPage as RulesPage }; diff --git a/x-pack/plugins/observability/public/pages/rules/state_container/index.tsx b/x-pack/plugins/observability/public/pages/rules/state_container/index.tsx deleted file mode 100644 index 7820342482035..0000000000000 --- a/x-pack/plugins/observability/public/pages/rules/state_container/index.tsx +++ /dev/null @@ -1,9 +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. - */ - -export { Provider, rulesPageStateContainer } from './state_container'; -export { useRulesPageStateContainer } from './use_rules_page_state_container'; diff --git a/x-pack/plugins/observability/public/pages/rules/state_container/state_container.tsx b/x-pack/plugins/observability/public/pages/rules/state_container/state_container.tsx deleted file mode 100644 index 039218add3508..0000000000000 --- a/x-pack/plugins/observability/public/pages/rules/state_container/state_container.tsx +++ /dev/null @@ -1,68 +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 { - createStateContainer, - createStateContainerReactHelpers, -} from '@kbn/kibana-utils-plugin/public'; -import { RuleStatus } from '@kbn/triggers-actions-ui-plugin/public'; - -interface RulesPageContainerState { - lastResponse: string[]; - status: RuleStatus[]; -} - -const defaultState: RulesPageContainerState = { - lastResponse: [], - status: [], -}; - -interface RulesPageStateTransitions { - setLastResponse: ( - state: RulesPageContainerState - ) => (lastResponse: string[]) => RulesPageContainerState; - setStatus: (state: RulesPageContainerState) => (status: RuleStatus[]) => RulesPageContainerState; -} - -const transitions: RulesPageStateTransitions = { - setLastResponse: (state) => (lastResponse) => { - const filteredIds = lastResponse; - lastResponse.forEach((id) => { - const isPreviouslyChecked = state.lastResponse.includes(id); - if (!isPreviouslyChecked) { - filteredIds.concat(id); - } else { - filteredIds.filter((val) => { - return val !== id; - }); - } - }); - return { ...state, lastResponse: filteredIds }; - }, - setStatus: (state) => (status) => { - const filteredIds = status; - status.forEach((id) => { - const isPreviouslyChecked = state.status.includes(id); - if (!isPreviouslyChecked) { - filteredIds.concat(id); - } else { - filteredIds.filter((val) => { - return val !== id; - }); - } - }); - return { ...state, status: filteredIds }; - }, -}; - -const rulesPageStateContainer = createStateContainer(defaultState, transitions); - -type RulesPageStateContainer = typeof rulesPageStateContainer; -const { Provider, useContainer } = createStateContainerReactHelpers(); - -export { Provider, rulesPageStateContainer, useContainer, defaultState }; -export type { RulesPageStateContainer, RulesPageContainerState, RulesPageStateTransitions }; diff --git a/x-pack/plugins/observability/public/pages/rules/state_container/use_rules_page_state_container.tsx b/x-pack/plugins/observability/public/pages/rules/state_container/use_rules_page_state_container.tsx deleted file mode 100644 index cd20de3f95c29..0000000000000 --- a/x-pack/plugins/observability/public/pages/rules/state_container/use_rules_page_state_container.tsx +++ /dev/null @@ -1,98 +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 { useEffect } from 'react'; -import { useHistory } from 'react-router-dom'; - -import { - createKbnUrlStateStorage, - syncState, - IKbnUrlStateStorage, - useContainerSelector, -} from '@kbn/kibana-utils-plugin/public'; - -import { - useContainer, - defaultState, - RulesPageStateContainer, - RulesPageContainerState, -} from './state_container'; - -export function useRulesPageStateContainer() { - const stateContainer = useContainer(); - - useUrlStateSyncEffect(stateContainer); - - const { setLastResponse, setStatus } = stateContainer.transitions; - const { lastResponse, status } = useContainerSelector(stateContainer, (state) => state); - - return { - lastResponse, - status, - setLastResponse, - setStatus, - }; -} - -function useUrlStateSyncEffect(stateContainer: RulesPageStateContainer) { - const history = useHistory(); - - useEffect(() => { - const urlStateStorage = createKbnUrlStateStorage({ - history, - useHash: false, - useHashQuery: false, - }); - const { start, stop } = setupUrlStateSync(stateContainer, urlStateStorage); - - start(); - - syncUrlStateWithInitialContainerState(stateContainer, urlStateStorage); - - return stop; - }, [stateContainer, history]); -} - -function setupUrlStateSync( - stateContainer: RulesPageStateContainer, - stateStorage: IKbnUrlStateStorage -) { - // This handles filling the state when an incomplete URL set is provided - const setWithDefaults = (changedState: Partial | null) => { - stateContainer.set({ ...defaultState, ...changedState }); - }; - return syncState({ - storageKey: '_a', - stateContainer: { - ...stateContainer, - set: setWithDefaults, - }, - stateStorage, - }); -} - -function syncUrlStateWithInitialContainerState( - stateContainer: RulesPageStateContainer, - urlStateStorage: IKbnUrlStateStorage -) { - const urlState = urlStateStorage.get>('_a'); - - if (urlState) { - const newState = { - ...defaultState, - ...urlState, - }; - - stateContainer.set(newState); - } else { - // Reset the state container when no URL state or timefilter range is set to avoid accidentally - // re-using state set on a previous visit to the page in the same session - stateContainer.set(defaultState); - } - - urlStateStorage.set('_a', stateContainer.get()); -} diff --git a/x-pack/plugins/observability/public/pages/rules/translations.ts b/x-pack/plugins/observability/public/pages/rules/translations.ts deleted file mode 100644 index 3287b7310c94b..0000000000000 --- a/x-pack/plugins/observability/public/pages/rules/translations.ts +++ /dev/null @@ -1,90 +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 { i18n } from '@kbn/i18n'; - -export const RULE_STATUS_LICENSE_ERROR = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusLicenseError', - { - defaultMessage: 'License Error', - } -); - -export const RULE_STATUS_OK = i18n.translate('xpack.observability.rules.rulesTable.ruleStatusOk', { - defaultMessage: 'Ok', -}); - -export const RULE_STATUS_ACTIVE = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusActive', - { - defaultMessage: 'Active', - } -); - -export const RULE_STATUS_ERROR = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusError', - { - defaultMessage: 'Error', - } -); - -export const RULE_STATUS_PENDING = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusPending', - { - defaultMessage: 'Pending', - } -); - -export const RULE_STATUS_UNKNOWN = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusUnknown', - { - defaultMessage: 'Unknown', - } -); - -export const RULE_STATUS_WARNING = i18n.translate( - 'xpack.observability.rules.rulesTable.ruleStatusWarning', - { - defaultMessage: 'warning', - } -); - -export const LAST_RESPONSE_COLUMN_TITLE = i18n.translate( - 'xpack.observability.rules.rulesTable.columns.lastResponseTitle', - { - defaultMessage: 'Last response', - } -); - -export const RULES_PAGE_TITLE = i18n.translate('xpack.observability.rulesTitle', { - defaultMessage: 'Rules', -}); - -export const RULES_BREADCRUMB_TEXT = i18n.translate( - 'xpack.observability.breadcrumbs.rulesLinkText', - { - defaultMessage: 'Rules', - } -); - -export const RULES_LOAD_ERROR = i18n.translate('xpack.observability.rules.loadError', { - defaultMessage: 'Unable to load rules', -}); - -export const RULE_TAGS_LOAD_ERROR = i18n.translate( - 'xpack.observability.rulesList.unableToLoadRuleTags', - { - defaultMessage: 'Unable to load rule tags', - } -); - -export const RULES_CHANGE_STATUS = i18n.translate( - 'xpack.observability.rules.rulesTable.changeStatusAriaLabel', - { - defaultMessage: 'Change status', - } -); diff --git a/x-pack/plugins/observability/public/routes/index.tsx b/x-pack/plugins/observability/public/routes/index.tsx index f28ea3bd2393b..f3057d6af7e8c 100644 --- a/x-pack/plugins/observability/public/routes/index.tsx +++ b/x-pack/plugins/observability/public/routes/index.tsx @@ -14,7 +14,7 @@ import { AlertsPage } from '../pages/alerts/alerts'; import { AlertDetails } from '../pages/alert_details/alert_details'; import { CasesPage } from '../pages/cases/cases'; import { OverviewPage } from '../pages/overview/overview'; -import { RulesPage } from '../pages/rules'; +import { RulesPage } from '../pages/rules/rules'; import { RuleDetailsPage } from '../pages/rule_details'; import { SlosPage } from '../pages/slos/slos'; import { SloDetailsPage } from '../pages/slo_details/slo_details'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 00e8a9054e9cc..ff49eebd283ad 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -24691,18 +24691,7 @@ "xpack.observability.rules.addRuleButtonLabel": "Créer une règle", "xpack.observability.rules.deleteSelectedIdsConfirmModal.cancelButtonLabel": "Annuler", "xpack.observability.rules.docsLinkText": "Documentation", - "xpack.observability.rules.loadError": "Impossible de charger les règles", - "xpack.observability.rules.rulesTable.changeStatusAriaLabel": "Modifier le statut", - "xpack.observability.rules.rulesTable.columns.lastResponseTitle": "Dernière réponse", - "xpack.observability.rules.rulesTable.ruleStatusActive": "Actif", - "xpack.observability.rules.rulesTable.ruleStatusError": "Erreur", - "xpack.observability.rules.rulesTable.ruleStatusLicenseError": "Erreur de licence", - "xpack.observability.rules.rulesTable.ruleStatusOk": "Ok", - "xpack.observability.rules.rulesTable.ruleStatusPending": "En attente", - "xpack.observability.rules.rulesTable.ruleStatusUnknown": "Inconnu", - "xpack.observability.rules.rulesTable.ruleStatusWarning": "avertissement", "xpack.observability.rulesLinkTitle": "Règles", - "xpack.observability.rulesList.unableToLoadRuleTags": "Impossible de charger les balises de règle", "xpack.observability.rulesTitle": "Règles", "xpack.observability.search.url.close": "Fermer", "xpack.observability.section.errorPanel": "Une erreur est survenue lors de la tentative de récupération des données. Réessayez plus tard", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a992f9035ba45..15cdae12baf57 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -24669,18 +24669,7 @@ "xpack.observability.rules.addRuleButtonLabel": "ルールを作成", "xpack.observability.rules.deleteSelectedIdsConfirmModal.cancelButtonLabel": "キャンセル", "xpack.observability.rules.docsLinkText": "ドキュメント", - "xpack.observability.rules.loadError": "ルールを読み込めません", - "xpack.observability.rules.rulesTable.changeStatusAriaLabel": "ステータスの変更", - "xpack.observability.rules.rulesTable.columns.lastResponseTitle": "前回の応答", - "xpack.observability.rules.rulesTable.ruleStatusActive": "アクティブ", - "xpack.observability.rules.rulesTable.ruleStatusError": "エラー", - "xpack.observability.rules.rulesTable.ruleStatusLicenseError": "ライセンスエラー", - "xpack.observability.rules.rulesTable.ruleStatusOk": "OK", - "xpack.observability.rules.rulesTable.ruleStatusPending": "保留中", - "xpack.observability.rules.rulesTable.ruleStatusUnknown": "不明", - "xpack.observability.rules.rulesTable.ruleStatusWarning": "警告", "xpack.observability.rulesLinkTitle": "ルール", - "xpack.observability.rulesList.unableToLoadRuleTags": "ルールタグを読み込めません", "xpack.observability.rulesTitle": "ルール", "xpack.observability.search.url.close": "閉じる", "xpack.observability.section.errorPanel": "データの取得時にエラーが発生しました。再試行してください", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index cd2fd87cef7f5..e6d8d9fd7b619 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -24700,18 +24700,7 @@ "xpack.observability.rules.addRuleButtonLabel": "创建规则", "xpack.observability.rules.deleteSelectedIdsConfirmModal.cancelButtonLabel": "取消", "xpack.observability.rules.docsLinkText": "文档", - "xpack.observability.rules.loadError": "无法加载规则", - "xpack.observability.rules.rulesTable.changeStatusAriaLabel": "更改状态", - "xpack.observability.rules.rulesTable.columns.lastResponseTitle": "上次响应", - "xpack.observability.rules.rulesTable.ruleStatusActive": "活动", - "xpack.observability.rules.rulesTable.ruleStatusError": "错误", - "xpack.observability.rules.rulesTable.ruleStatusLicenseError": "许可证错误", - "xpack.observability.rules.rulesTable.ruleStatusOk": "确定", - "xpack.observability.rules.rulesTable.ruleStatusPending": "待处理", - "xpack.observability.rules.rulesTable.ruleStatusUnknown": "未知", - "xpack.observability.rules.rulesTable.ruleStatusWarning": "警告", "xpack.observability.rulesLinkTitle": "规则", - "xpack.observability.rulesList.unableToLoadRuleTags": "无法加载规则标签", "xpack.observability.rulesTitle": "规则", "xpack.observability.search.url.close": "关闭", "xpack.observability.section.errorPanel": "尝试提取数据时发生错误。请重试", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx index 4fc42cea86872..db4819052eae3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx @@ -394,7 +394,7 @@ export const RulesList = ({ if (lastRunOutcomeFilter) { updateFilters({ filter: 'ruleLastRunOutcomes', value: lastRunOutcomeFilter }); } - }, [lastResponseFilter]); + }, [lastRunOutcomeFilter]); useEffect(() => { if (cloneRuleId.current) {