[SLO] Introduce URl state manager for definition filter, move outdated view to management page (#216367)

## Summary

Resolves #214260

<img width="1416" alt="Screenshot 2025-03-31 at 11 26 56 PM"
src="https://github.com/user-attachments/assets/d2e048b6-dddd-4127-b551-5a2aae57dbe4"
/>

This PR merges the outdated SLO view with the new SLO management table.
As part of the implementation of the issue, useState hooks have been
replaced with url state management hooks, and the SLO definition API has
been updated to provide the user with the option to pull either outdated
or current definitions. By not providing this value, the user will
receive all definitions.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Bailey Cash 2025-04-01 16:09:59 -04:00 committed by GitHub
parent 94ca17f521
commit a382856f71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 188 additions and 422 deletions

View file

@ -42391,7 +42391,6 @@
"xpack.slo.breadcrumbs.sloEditLabel": "Modifier",
"xpack.slo.breadcrumbs.sloLabel": "SLO",
"xpack.slo.breadcrumbs.slosLinkText": "SLO",
"xpack.slo.breadcrumbs.slosOutdatedDefinitions": "Définitions de SLO obsolètes",
"xpack.slo.breadcrumbs.slosSettingsText": "Paramètres du SLO",
"xpack.slo.budgetingMethod.occurrences": "Occurrences",
"xpack.slo.budgetingMethod.timeslices": "Intervalles de temps",
@ -42994,14 +42993,6 @@
"xpack.slo.sloOverviewDetails.button.detailsLabel": "Détails",
"xpack.slo.sloOverviewDetails.h2.detailsLabel": "{sloName}",
"xpack.slo.sloSettings.": "Paramètres du SLO [id={id}]",
"xpack.slo.slosOutdatedDefinitions.deleteButtonLabel": "Supprimer",
"xpack.slo.slosOutdatedDefinitions.description": "Les SLO suivants proviennent d'une version antérieure et doivent être réinitialisés et mis à niveau vers la dernière version, OU effacés et supprimés du système. Lors de la réinitialisation du SLO, la transformation sera mise à jour vers la dernière version et les données historiques seront régénérées à partir des données source.",
"xpack.slo.slosOutdatedDefinitions.licenseError": "Il vous faut une licence platinum ou supérieure pour pouvoir accéder à cette page",
"xpack.slo.slosOutdatedDefinitions.pageTitle": "Définitions de SLO obsolètes",
"xpack.slo.slosOutdatedDefinitions.refreshButtonLabel": "Actualiser",
"xpack.slo.slosOutdatedDefinitions.resetButtonLabel": "Réinitialiser",
"xpack.slo.slosOutdatedDefinitions.sloPermissionsError": "Il vous faut les autorisations d'écriture pour les SLO afin de pouvoir accéder à cette page",
"xpack.slo.slosOutdatedDefinitions.updateButtonLabel": "Mettre à jour",
"xpack.slo.sLOsOverview.euiStat.burnRateActiveAlerts": "Alertes actives",
"xpack.slo.sLOsOverview.euiStat.burnRateRecoveredAlerts": "Alertes récupérées",
"xpack.slo.sLOsOverview.euiStat.burnRateRules": "Règles",

View file

@ -42361,7 +42361,6 @@
"xpack.slo.breadcrumbs.sloEditLabel": "編集",
"xpack.slo.breadcrumbs.sloLabel": "SLO",
"xpack.slo.breadcrumbs.slosLinkText": "SLO",
"xpack.slo.breadcrumbs.slosOutdatedDefinitions": "古いSLO定義",
"xpack.slo.breadcrumbs.slosSettingsText": "SLO設定",
"xpack.slo.budgetingMethod.occurrences": "出現回数",
"xpack.slo.budgetingMethod.timeslices": "タイムスライス",
@ -42963,14 +42962,6 @@
"xpack.slo.sloOverviewDetails.button.detailsLabel": "詳細",
"xpack.slo.sloOverviewDetails.h2.detailsLabel": "{sloName}",
"xpack.slo.sloSettings.": "SLO設定 [id={id}]",
"xpack.slo.slosOutdatedDefinitions.deleteButtonLabel": "削除",
"xpack.slo.slosOutdatedDefinitions.description": "次のSLOは以前のバージョンであり、リセットして最新バージョンにアップグレードするか、削除してシステムから除去する必要があります。SLOをリセットすると、変換が最新バージョンに更新され、履歴データがソースデータから再生成されます。",
"xpack.slo.slosOutdatedDefinitions.licenseError": "このページにアクセスするには、少なくともプラチナライセンスが必要です",
"xpack.slo.slosOutdatedDefinitions.pageTitle": "古いSLO定義",
"xpack.slo.slosOutdatedDefinitions.refreshButtonLabel": "更新",
"xpack.slo.slosOutdatedDefinitions.resetButtonLabel": "リセット",
"xpack.slo.slosOutdatedDefinitions.sloPermissionsError": "このページにアクセスするには、SLOの書き込み権限が必要です",
"xpack.slo.slosOutdatedDefinitions.updateButtonLabel": "更新",
"xpack.slo.sLOsOverview.euiStat.burnRateActiveAlerts": "アクティブアラート",
"xpack.slo.sLOsOverview.euiStat.burnRateRecoveredAlerts": "回復されたアラート",
"xpack.slo.sLOsOverview.euiStat.burnRateRules": "ルール",

View file

@ -42428,7 +42428,6 @@
"xpack.slo.breadcrumbs.sloEditLabel": "编辑",
"xpack.slo.breadcrumbs.sloLabel": "SLO",
"xpack.slo.breadcrumbs.slosLinkText": "SLO",
"xpack.slo.breadcrumbs.slosOutdatedDefinitions": "过时的 SLO 定义",
"xpack.slo.breadcrumbs.slosSettingsText": "SLO 设置",
"xpack.slo.budgetingMethod.occurrences": "发生次数",
"xpack.slo.budgetingMethod.timeslices": "时间片",
@ -43031,14 +43030,6 @@
"xpack.slo.sloOverviewDetails.button.detailsLabel": "详情",
"xpack.slo.sloOverviewDetails.h2.detailsLabel": "{sloName}",
"xpack.slo.sloSettings.": "SLO 设置 [id={id}]",
"xpack.slo.slosOutdatedDefinitions.deleteButtonLabel": "删除",
"xpack.slo.slosOutdatedDefinitions.description": "以下 SLO 来自上一版本,需要进行重置以升级到最新版本,或将其从系统中删除和移除。重置 SLO 时,转换将更新到最新版本,并会重新从源数据生成历史数据。",
"xpack.slo.slosOutdatedDefinitions.licenseError": "必须至少具有白金级许可证才能访问此页面",
"xpack.slo.slosOutdatedDefinitions.pageTitle": "过时的 SLO 定义",
"xpack.slo.slosOutdatedDefinitions.refreshButtonLabel": "刷新",
"xpack.slo.slosOutdatedDefinitions.resetButtonLabel": "重置",
"xpack.slo.slosOutdatedDefinitions.sloPermissionsError": "必须具有 SLO 的写入权限才能访问此页面",
"xpack.slo.slosOutdatedDefinitions.updateButtonLabel": "更新",
"xpack.slo.sLOsOverview.euiStat.burnRateActiveAlerts": "活动告警",
"xpack.slo.sLOsOverview.euiStat.burnRateRecoveredAlerts": "已恢复告警",
"xpack.slo.sLOsOverview.euiStat.burnRateRules": "规则",

View file

@ -22,7 +22,6 @@ export const paths = {
slosSettings: `${SLOS_BASE_PATH}${SLO_SETTINGS_PATH}`,
slosWelcome: `${SLOS_BASE_PATH}${SLOS_WELCOME_PATH}`,
slosManagement: `${SLOS_BASE_PATH}${SLOS_MANAGEMENT_PATH}`,
slosOutdatedDefinitions: `${SLOS_BASE_PATH}${SLOS_OUTDATED_DEFINITIONS_PATH}`,
sloCreate: `${SLOS_BASE_PATH}${SLO_CREATE_PATH}`,
sloCreateWithEncodedForm: (encodedParams: string) =>
`${SLOS_BASE_PATH}${SLO_CREATE_PATH}?_a=${encodedParams}`,

View file

@ -8,6 +8,7 @@ import { EuiButton, EuiCallOut, EuiSpacer } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { encode } from '@kbn/rison';
import { useKibana } from '../../../hooks/use_kibana';
import { useFetchSloDefinitions } from '../../../hooks/use_fetch_slo_definitions';
import { paths } from '../../../../common/locators/paths';
@ -19,7 +20,11 @@ export function SloOutdatedCallout() {
} = useKibana().services;
const handleClick = () => {
navigateToUrl(basePath.prepend(paths.slosOutdatedDefinitions));
navigateToUrl(
`${basePath.prepend(paths.slosManagement)}?search=${encode({
includeOutdatedOnly: true,
})}`
);
};
const { isLoading, data } = useFetchSloDefinitions({ includeOutdatedOnly: true });

View file

@ -45,7 +45,7 @@ export function useFetchSloDefinitions({
params: {
query: {
...(search !== undefined && { search }),
...(includeOutdatedOnly !== undefined && { includeOutdatedOnly }),
...(!!includeOutdatedOnly && { includeOutdatedOnly }),
...(validTags?.length && { tags: validTags }),
...(page !== undefined && { page: String(page) }),
...(perPage !== undefined && { perPage: String(perPage) }),

View file

@ -0,0 +1,88 @@
/*
* 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 {
createKbnUrlStateStorage,
createSessionStorageStateStorage,
} from '@kbn/kibana-utils-plugin/public';
import deepmerge from 'deepmerge';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { DEFAULT_SLO_PAGE_SIZE } from '../../../../../common/constants';
export const SLO_MANAGEMENT_SEARCH_URL_STORAGE_KEY = 'search';
export const SLO_MANAGEMENT_SEARCH_SESSION_STORAGE_KEY = 'slo.management_page_search_state';
export interface SearchState {
search: string;
tags: string[];
page: number;
perPage: number;
includeOutdatedOnly?: boolean;
}
export const DEFAULT_STATE: SearchState = {
search: '',
tags: [],
page: 0,
perPage: DEFAULT_SLO_PAGE_SIZE,
includeOutdatedOnly: false,
};
export function useUrlSearchState(): {
state: SearchState;
onStateChange: (state: Partial<SearchState>) => void;
} {
const [state, setState] = useState<SearchState>(DEFAULT_STATE);
const history = useHistory();
const urlStateStorage = useRef(
createKbnUrlStateStorage({
history,
useHash: false,
useHashQuery: false,
})
);
const sessionStorage = useRef(createSessionStorageStateStorage(window.localStorage));
useEffect(() => {
const sub = urlStateStorage.current
?.change$<SearchState>(SLO_MANAGEMENT_SEARCH_URL_STORAGE_KEY)
.subscribe((newSearchState) => {
if (newSearchState) {
setState(newSearchState);
}
});
setState(
urlStateStorage.current?.get<SearchState>(SLO_MANAGEMENT_SEARCH_URL_STORAGE_KEY) ??
sessionStorage.current?.get<SearchState>(SLO_MANAGEMENT_SEARCH_SESSION_STORAGE_KEY) ??
DEFAULT_STATE
);
return () => {
sub?.unsubscribe();
};
}, [urlStateStorage, sessionStorage]);
const onStateChange = useCallback(
(newState: Partial<SearchState>) => {
const updatedState = { ...state, page: 0, ...newState };
setState(() => updatedState);
urlStateStorage.current?.set(SLO_MANAGEMENT_SEARCH_URL_STORAGE_KEY, updatedState, {
replace: true,
});
},
[state]
);
return {
state: deepmerge(DEFAULT_STATE, state),
onStateChange,
};
}

View file

@ -7,10 +7,12 @@
import { EuiFlexGroup } from '@elastic/eui';
import React from 'react';
import { SloManagementTable } from './slo_management_table';
import { SloOutdatedFilterCallout } from './slo_management_outdated_filter_callout';
export function SloManagementContent() {
return (
<EuiFlexGroup direction="column" gutterSize="s">
<SloOutdatedFilterCallout />
<SloManagementTable />
</EuiFlexGroup>
);

View file

@ -0,0 +1,46 @@
/*
* 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 { EuiCallOut, EuiIcon, EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { useUrlSearchState } from './hooks/use_url_search_state';
export function SloOutdatedFilterCallout() {
const { state, onStateChange } = useUrlSearchState();
if (!state.includeOutdatedOnly) {
return null;
}
return (
<>
<EuiCallOut color="primary">
<EuiText>
<EuiIcon type="iInCircle" />{' '}
{i18n.translate('xpack.slo.outdatedSloFilterCallout.title', {
defaultMessage:
"You're currently viewing only outdated SLOs. You can reset them from the action menu to bring them up to date.",
})}{' '}
<EuiLink
data-test-subj="outdated-filter-help-callout"
onClick={() => {
onStateChange({
...state,
includeOutdatedOnly: false,
});
}}
>
{i18n.translate('xpack.slo.outdatedSloFilterCallout.action', {
defaultMessage: 'Remove filter',
})}
</EuiLink>
</EuiText>
</EuiCallOut>
<EuiSpacer size="m" />
</>
);
}

View file

@ -11,17 +11,14 @@ import { EuiComboBox, EuiComboBoxOptionOption, EuiText } from '@elastic/eui';
import { observabilityAppId } from '@kbn/observability-shared-plugin/common';
import { useFetchSLOSuggestions } from '../../slo_edit/hooks/use_fetch_suggestions';
import { useKibana } from '../../../hooks/use_kibana';
import { useUrlSearchState } from './hooks/use_url_search_state';
interface Props {
filters: {
search: string;
tags: string[];
};
setFilters: Function;
onRefresh: () => void;
}
export function SloManagementSearchBar({ filters, setFilters, onRefresh }: Props) {
export function SloManagementSearchBar({ onRefresh }: Props) {
const { state, onStateChange } = useUrlSearchState();
const {
unifiedSearch: {
ui: { SearchBar },
@ -46,25 +43,30 @@ export function SloManagementSearchBar({ filters, setFilters, onRefresh }: Props
showDatePicker={false}
showSavedQueryControls={false}
showFilterBar={false}
query={{ query: filters.search, language: 'text' }}
query={{ query: state.search, language: 'text' }}
onQuerySubmit={({ query: value }) => {
setFilters({ search: value?.query, tags: filters.tags });
onStateChange({ ...state, search: value?.query ? (value?.query as string) : '' });
}}
onRefresh={onRefresh}
renderQueryInputAppend={() => (
<EuiComboBox
aria-label={filterTagsLabel}
placeholder={filterTagsLabel}
delimiter=","
options={suggestions?.tags ? [existOption, ...suggestions?.tags] : []}
selectedOptions={selectedOptions}
onChange={(newOptions) => {
setSelectedOptions(newOptions);
setFilters({ search: filters.search, tags: newOptions.map((option) => option.value) });
}}
isClearable={true}
data-test-subj="filter-slos-by-tag"
/>
<>
<EuiComboBox
aria-label={filterTagsLabel}
placeholder={filterTagsLabel}
delimiter=","
options={suggestions?.tags ? [existOption, ...suggestions?.tags] : []}
selectedOptions={selectedOptions}
onChange={(newOptions) => {
setSelectedOptions(newOptions);
onStateChange({
...state,
tags: newOptions.map((option) => String(option.value)),
});
}}
isClearable={true}
data-test-subj="filter-slos-by-tag"
/>
</>
)}
/>
);

View file

@ -36,19 +36,11 @@ import { SloResetConfirmationModal } from '../../../components/slo/reset_confirm
import { SloEnableConfirmationModal } from '../../../components/slo/enable_confirmation_modal/slo_enable_confirmation_modal';
import { SloDisableConfirmationModal } from '../../../components/slo/disable_confirmation_modal/slo_disable_confirmation_modal';
import { SLO_MODEL_VERSION } from '../../../../common/constants';
interface SearchFilters {
search: string;
tags: string[];
}
import { useUrlSearchState } from './hooks/use_url_search_state';
export function SloManagementTable() {
const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [filters, setFilters] = useState<SearchFilters>({
search: '',
tags: [],
});
const { state, onStateChange } = useUrlSearchState();
const { search, page, perPage, tags, includeOutdatedOnly } = state;
const { services } = useKibana();
const {
@ -57,10 +49,11 @@ export function SloManagementTable() {
} = services;
const { isLoading, isError, data, refetch } = useFetchSloDefinitions({
name: filters.search,
page: pageIndex + 1,
perPage: pageSize,
tags: filters.tags,
page: page + 1,
perPage,
name: search,
tags,
includeOutdatedOnly,
});
const { data: permissions } = usePermissions();
@ -275,17 +268,21 @@ export function SloManagementTable() {
},
];
const onTableChange = ({ page }: Criteria<SLODefinitionResponse>) => {
if (page) {
const { index, size } = page;
setPageIndex(index);
setPageSize(size);
const onTableChange = ({ page: newPage }: Criteria<SLODefinitionResponse>) => {
if (newPage) {
const { index, size } = newPage;
const newState = {
...state,
page: index,
perPage: size,
};
onStateChange(newState);
}
};
const pagination = {
pageIndex,
pageSize,
pageIndex: page,
pageSize: perPage,
totalItemCount: data?.total ?? 0,
pageSizeOptions: [10, 25, 50, 100],
showPerPageOptions: true,
@ -294,7 +291,7 @@ export function SloManagementTable() {
return (
<>
<EuiPanel hasBorder={true}>
<SloManagementSearchBar filters={filters} setFilters={setFilters} onRefresh={refetch} />
<SloManagementSearchBar onRefresh={refetch} />
<EuiSpacer size="m" />
<EuiBasicTable<SLODefinitionResponse>
tableCaption={TABLE_CAPTION}

View file

@ -1,138 +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 { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTablePagination, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';
import React, { useState } from 'react';
import { paths } from '../../../common/locators/paths';
import { HeaderMenu } from '../../components/header_menu/header_menu';
import { useFetchSloDefinitions } from '../../hooks/use_fetch_slo_definitions';
import { useLicense } from '../../hooks/use_license';
import { usePermissions } from '../../hooks/use_permissions';
import { usePluginContext } from '../../hooks/use_plugin_context';
import { useKibana } from '../../hooks/use_kibana';
import { SloListEmpty } from '../slos/components/slo_list_empty';
import { OutdatedSlo } from './outdated_slo';
import { OutdatedSloSearchBar } from './outdated_slo_search_bar';
export function SlosOutdatedDefinitions() {
const {
http: { basePath },
serverless,
} = useKibana().services;
const { data: permissions } = usePermissions();
const { ObservabilityPageTemplate } = usePluginContext();
const { hasAtLeast } = useLicense();
useBreadcrumbs(
[
{
href: basePath.prepend(paths.slos),
text: i18n.translate('xpack.slo.breadcrumbs.slosLinkText', {
defaultMessage: 'SLOs',
}),
deepLinkId: 'slo',
},
{
text: i18n.translate('xpack.slo.breadcrumbs.slosOutdatedDefinitions', {
defaultMessage: 'Outdated SLO Definitions',
}),
},
],
{ serverless }
);
const [search, setSearch] = useState<string>('');
const [activePage, setActivePage] = useState<number>(0);
const [perPage, setPerPage] = useState<number>(10);
const handlePerPageChange = (perPageNumber: number) => {
setPerPage(perPageNumber);
setActivePage(0);
};
const { isLoading, data, refetch } = useFetchSloDefinitions({
name: search,
includeOutdatedOnly: true,
page: activePage + 1,
perPage,
});
const { total } = data ?? { total: 0 };
const hasRequiredWritePrivileges = permissions?.hasAllWriteRequested === true;
const hasPlatinumLicense = hasAtLeast('platinum') === true;
const errors = !hasRequiredWritePrivileges ? (
<EuiText>
{i18n.translate('xpack.slo.slosOutdatedDefinitions.sloPermissionsError', {
defaultMessage: 'You must have write permissions for SLOs to access this page',
})}
</EuiText>
) : !hasPlatinumLicense ? (
<EuiText>
{i18n.translate('xpack.slo.slosOutdatedDefinitions.licenseError', {
defaultMessage: 'You must have atleast a platinum license to access this page',
})}
</EuiText>
) : null;
return (
<ObservabilityPageTemplate
data-test-subj="slosOutdatedDefinitions"
pageHeader={{
pageTitle: i18n.translate('xpack.slo.slosOutdatedDefinitions.pageTitle', {
defaultMessage: 'Outdated SLO Definitions',
}),
}}
>
<HeaderMenu />
{!!errors ? (
errors
) : (
<>
<p>
{i18n.translate('xpack.slo.slosOutdatedDefinitions.description', {
defaultMessage:
'The following SLOs are from a previous version and need to either be reset to upgrade to the latest version OR deleted and removed from the system. When you reset the SLO, the transform will be updated to the latest version and the historical data will be regenerated from the source data.',
})}
</p>
<EuiSpacer size="l" />
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<OutdatedSloSearchBar
initialSearch={search}
onRefresh={refetch}
onSearch={setSearch}
/>
</EuiFlexItem>
{!isLoading && total === 0 && <SloListEmpty />}
{!isLoading &&
total > 0 &&
data &&
data.results.map((slo) => (
<OutdatedSlo slo={slo} onDelete={refetch} onReset={refetch} />
))}
</EuiFlexGroup>
<EuiSpacer size="m" />
{!isLoading && data && (
<EuiTablePagination
activePage={activePage}
pageCount={Math.ceil(total / perPage)}
itemsPerPage={perPage}
onChangePage={setActivePage}
onChangeItemsPerPage={handlePerPageChange}
itemsPerPageOptions={[10, 20, 50, 100]}
/>
)}
</>
)}
</ObservabilityPageTemplate>
);
}

View file

@ -1,117 +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 { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { SLODefinitionResponse } from '@kbn/slo-schema';
import React, { useState } from 'react';
import { SloDeleteModal } from '../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal';
import { SloResetConfirmationModal } from '../../components/slo/reset_confirmation_modal/slo_reset_confirmation_modal';
import { useResetSlo } from '../../hooks/use_reset_slo';
import { SloIndicatorTypeBadge } from '../slos/components/badges/slo_indicator_type_badge';
import { SloTimeWindowBadge } from '../slos/components/badges/slo_time_window_badge';
interface OutdatedSloProps {
slo: SLODefinitionResponse;
onReset: () => void;
onDelete: () => void;
}
export function OutdatedSlo({ slo, onReset, onDelete }: OutdatedSloProps) {
const { mutateAsync: resetSlo, isLoading: isResetLoading } = useResetSlo();
const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false);
const [isResetConfirmationModalOpen, setResetConfirmationModalOpen] = useState(false);
const handleDelete = () => {
setDeleteConfirmationModalOpen(true);
};
const handleDeleteConfirm = async () => {
setDeleteConfirmationModalOpen(false);
onDelete();
};
const handleDeleteCancel = () => {
setDeleteConfirmationModalOpen(false);
};
const handleReset = () => {
setResetConfirmationModalOpen(true);
};
const handleResetConfirm = async () => {
setResetConfirmationModalOpen(false);
await resetSlo({ id: slo.id, name: slo.name });
onReset();
};
const handleResetCancel = () => {
setResetConfirmationModalOpen(false);
};
return (
<EuiPanel hasBorder hasShadow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem>
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<EuiText>
<span>{slo.name}</span>
</EuiText>
</EuiFlexItem>
<EuiFlexGroup
direction="row"
responsive={false}
gutterSize="s"
alignItems="center"
wrap
>
<SloIndicatorTypeBadge slo={slo} />
<SloTimeWindowBadge slo={slo} />
</EuiFlexGroup>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={0}>
<EuiButton
data-test-subj="o11ySlosOutdatedDefinitionsResetButton"
color="primary"
fill
isLoading={isResetLoading}
onClick={handleReset}
>
<FormattedMessage
id="xpack.slo.slosOutdatedDefinitions.resetButtonLabel"
defaultMessage="Reset"
/>
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={0}>
<EuiButton
data-test-subj="o11ySlosOutdatedDefinitionsDeleteButton"
color="danger"
fill
onClick={handleDelete}
>
<FormattedMessage
id="xpack.slo.slosOutdatedDefinitions.deleteButtonLabel"
defaultMessage="Delete"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
{isDeleteConfirmationModalOpen ? (
<SloDeleteModal slo={slo} onCancel={handleDeleteCancel} onSuccess={handleDeleteConfirm} />
) : null}
{isResetConfirmationModalOpen ? (
<SloResetConfirmationModal
slo={slo}
onCancel={handleResetCancel}
onConfirm={handleResetConfirm}
/>
) : null}
</EuiPanel>
);
}

View file

@ -1,82 +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 React, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiFieldSearch } from '@elastic/eui';
interface OutdatedSloSearchBarProps {
initialSearch?: string;
onRefresh: () => void;
onSearch: (search: string) => void;
}
export function OutdatedSloSearchBar({
onSearch,
onRefresh,
initialSearch = '',
}: OutdatedSloSearchBarProps) {
const [tempSearch, setTempSearch] = useState<string>(initialSearch);
const [search, setSearch] = useState<string>(initialSearch);
const refreshOrUpdateSearch = () => {
if (tempSearch !== search) {
setSearch(tempSearch);
onSearch(tempSearch);
} else {
onRefresh();
}
};
const handleClick = (event: React.ChangeEvent<HTMLInputElement>) =>
setTempSearch(event.target.value);
const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
refreshOrUpdateSearch();
}
};
return (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFieldSearch
data-test-subj="o11ySlosOutdatedDefinitionsFieldSearch"
fullWidth
value={tempSearch}
onChange={handleClick}
onKeyDown={handleKeyPress}
/>
</EuiFlexItem>
<EuiFlexItem grow={0}>
{search === tempSearch && (
<EuiButton
data-test-subj="o11ySlosOutdatedDefinitionsRefreshButton"
iconType="refresh"
onClick={refreshOrUpdateSearch}
>
{i18n.translate('xpack.slo.slosOutdatedDefinitions.refreshButtonLabel', {
defaultMessage: 'Refresh',
})}
</EuiButton>
)}
{search !== tempSearch && (
<EuiButton
data-test-subj="o11ySlosOutdatedDefinitionsUpdateButton"
iconType="kqlFunction"
color="success"
fill
onClick={refreshOrUpdateSearch}
>
{i18n.translate('xpack.slo.slosOutdatedDefinitions.updateButtonLabel', {
defaultMessage: 'Update',
})}
</EuiButton>
)}
</EuiFlexItem>
</EuiFlexGroup>
);
}

View file

@ -12,7 +12,6 @@ import { SloDetailsPage } from '../pages/slo_details/slo_details';
import { SloEditPage } from '../pages/slo_edit/slo_edit';
import {
SLOS_MANAGEMENT_PATH,
SLOS_OUTDATED_DEFINITIONS_PATH,
SLOS_PATH,
SLOS_WELCOME_PATH,
SLO_CREATE_PATH,
@ -20,7 +19,6 @@ import {
SLO_EDIT_PATH,
SLO_SETTINGS_PATH,
} from '../../common/locators/paths';
import { SlosOutdatedDefinitions } from '../pages/slo_outdated_definitions';
import { SloSettingsPage } from '../pages/slo_settings/slo_settings';
import { ExperimentalFeatures } from '../../common/config';
import { SloManagementPage } from '../pages/slo_management/slo_management_page';
@ -57,13 +55,6 @@ export const getRoutes = (
params: {},
exact: true,
},
[SLOS_OUTDATED_DEFINITIONS_PATH]: {
handler: () => {
return <SlosOutdatedDefinitions />;
},
params: {},
exact: true,
},
[SLO_EDIT_PATH]: {
handler: () => {
return <SloEditPage />;

View file

@ -116,9 +116,9 @@ export class KibanaSavedObjectsSLORepository implements SLORepository {
search: string,
pagination: Pagination,
options: {
includeOutdatedOnly: boolean;
includeOutdatedOnly?: boolean;
tags: string[];
} = { includeOutdatedOnly: false, tags: [] }
} = { tags: [] }
): Promise<Paginated<SLODefinition>> {
const { includeOutdatedOnly, tags } = options;
const filter = [];