diff --git a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx
index 534cd48ade81f..86ebf06c2b84e 100644
--- a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx
+++ b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx
@@ -14,7 +14,7 @@ import { I18nProvider } from '@kbn/i18n-react';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public';
import { buildExistsFilter } from '@kbn/es-query';
-import { EuiComboBox } from '@elastic/eui';
+import { EuiButton, EuiComboBox } from '@elastic/eui';
import { SearchBar, SearchBarProps } from '../search_bar';
import { setIndexPatterns } from '../services';
@@ -695,4 +695,20 @@ storiesOf('SearchBar', module)
},
submitButtonStyle: 'full',
})
+ )
+
+ .add('with renderQueryInputAppend prop', () =>
+ wrapSearchBarInContext({
+ dataViewPickerComponentProps: {
+ currentDataViewId: '1234',
+ trigger: {
+ 'data-test-subj': 'dataView-switch-link',
+ label: 'logstash-*',
+ title: 'logstash-*',
+ },
+ onChangeDataView: action('onChangeDataView'),
+ },
+ submitButtonStyle: 'full',
+ renderQueryInputAppend: () => {}}>Append,
+ })
);
diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_menu.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_menu.tsx
index 9f84aa3096213..14b11737e8844 100644
--- a/src/plugins/unified_search/public/query_string_input/query_bar_menu.tsx
+++ b/src/plugins/unified_search/public/query_string_input/query_bar_menu.tsx
@@ -70,6 +70,7 @@ export interface QueryBarMenuProps extends WithCloseFilterEditorConfirmModalProp
buttonProps?: Partial;
isDisabled?: boolean;
suggestionsAbstraction?: SuggestionsAbstraction;
+ renderQueryInputAppend?: () => React.ReactNode;
}
function QueryBarMenuComponent({
diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx
index bd0ffc12565a0..4b63ed3e1ad28 100644
--- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx
+++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx
@@ -163,6 +163,7 @@ export interface QueryBarTopRowProps
onTextLangQuerySubmit: (query?: Query | AggregateQuery) => void;
onTextLangQueryChange: (query: AggregateQuery) => void;
submitOnBlur?: boolean;
+ renderQueryInputAppend?: () => React.ReactNode;
}
export const SharingMetaFields = React.memo(function SharingMetaFields({
@@ -702,6 +703,7 @@ export const QueryBarTopRow = React.memo(
? renderTextLangEditor()
: null}
+ {props.renderQueryInputAppend?.()}
{shouldShowDatePickerAsBadge() && props.filterBar}
{renderUpdateButton()}
diff --git a/src/plugins/unified_search/public/search_bar/search_bar.tsx b/src/plugins/unified_search/public/search_bar/search_bar.tsx
index 0372775922120..7d3c712181c0e 100644
--- a/src/plugins/unified_search/public/search_bar/search_bar.tsx
+++ b/src/plugins/unified_search/public/search_bar/search_bar.tsx
@@ -120,6 +120,8 @@ export interface SearchBarOwnProps {
isDisabled?: boolean;
submitOnBlur?: boolean;
+
+ renderQueryInputAppend?: () => React.ReactNode;
}
export type SearchBarProps = SearchBarOwnProps &
@@ -524,6 +526,7 @@ class SearchBarUI extends C
: undefined
}
suggestionsAbstraction={this.props.suggestionsAbstraction}
+ renderQueryInputAppend={this.props.renderQueryInputAppend}
/>
) : undefined;
@@ -610,6 +613,7 @@ class SearchBarUI extends C
onTextLangQueryChange={this.onTextLangQueryChange}
submitOnBlur={this.props.submitOnBlur}
suggestionsAbstraction={this.props.suggestionsAbstraction}
+ renderQueryInputAppend={this.props.renderQueryInputAppend}
/>
);
diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts
index 38233d2982c08..4f72827957ef7 100644
--- a/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts
+++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts
@@ -87,6 +87,7 @@ const sortBySchema = t.union([
const findSLOParamsSchema = t.partial({
query: t.partial({
+ filters: t.string,
kqlQuery: t.string,
page: t.string,
perPage: t.string,
diff --git a/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx b/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx
deleted file mode 100644
index dbd45bf74dee4..0000000000000
--- a/x-pack/plugins/observability/public/components/slo/feedback_button/feedback_button.tsx
+++ /dev/null
@@ -1,33 +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 from 'react';
-import { EuiButton } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-
-const SLO_FEEDBACK_LINK = 'https://ela.st/slo-feedback';
-
-interface Props {
- disabled?: boolean;
-}
-
-export function FeedbackButton({ disabled }: Props) {
- return (
-
- {i18n.translate('xpack.observability.slo.feedbackButtonLabel', {
- defaultMessage: 'Tell us what you think!',
- })}
-
- );
-}
diff --git a/x-pack/plugins/observability/public/components/slo/slo_outdated_callout/index.tsx b/x-pack/plugins/observability/public/components/slo/slo_outdated_callout/index.tsx
index dae8f76fb85a5..de09904d0637c 100644
--- a/x-pack/plugins/observability/public/components/slo/slo_outdated_callout/index.tsx
+++ b/x-pack/plugins/observability/public/components/slo/slo_outdated_callout/index.tsx
@@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import { EuiButton, EuiCallOut } from '@elastic/eui';
+import { EuiButton, EuiCallOut, EuiSpacer } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
@@ -25,37 +25,40 @@ export function SloOutdatedCallout() {
const { isLoading, data } = useFetchSloDefinitions({ includeOutdatedOnly: true });
if (!isLoading && data && data.total > 0) {
return (
-
-
-
-
-
-
+ <>
+
+
-
-
-
+
+
+
+
+
+
+
+
+ >
);
}
return null;
diff --git a/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts b/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts
index 8f687abda8805..c0be8dfd5f6e2 100644
--- a/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts
+++ b/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts
@@ -13,6 +13,8 @@ interface SloListFilter {
perPage: number;
sortBy: string;
sortDirection: string;
+ filters: string;
+ lastRefresh?: number;
}
export const sloKeys = {
diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts
index 5b1296fed67c2..56169bb1dd7fc 100644
--- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts
+++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts
@@ -8,9 +8,13 @@
import { i18n } from '@kbn/i18n';
import { FindSLOResponse } from '@kbn/slo-schema';
import { useQuery, useQueryClient } from '@tanstack/react-query';
-import { useState } from 'react';
-import { DEFAULT_SLO_PAGE_SIZE } from '../../../common/slo/constants';
-import { SLO_LONG_REFETCH_INTERVAL, SLO_SHORT_REFETCH_INTERVAL } from '../../constants';
+import { useMemo } from 'react';
+import { buildQueryFromFilters, Filter } from '@kbn/es-query';
+import { useCreateDataView } from '../use_create_data_view';
+import {
+ DEFAULT_SLO_PAGE_SIZE,
+ SLO_SUMMARY_DESTINATION_INDEX_NAME,
+} from '../../../common/slo/constants';
import { useKibana } from '../../utils/kibana_react';
import { sloKeys } from './query_key_factory';
@@ -20,8 +24,9 @@ interface SLOListParams {
page?: number;
sortBy?: string;
sortDirection?: 'asc' | 'desc';
- shouldRefetch?: boolean;
perPage?: number;
+ filters?: Filter[];
+ lastRefresh?: number;
}
export interface UseFetchSloListResponse {
@@ -38,37 +43,57 @@ export function useFetchSloList({
page = 1,
sortBy = 'status',
sortDirection = 'desc',
- shouldRefetch,
perPage = DEFAULT_SLO_PAGE_SIZE,
+ filters: filterDSL = [],
+ lastRefresh,
}: SLOListParams = {}): UseFetchSloListResponse {
const {
http,
notifications: { toasts },
} = useKibana().services;
const queryClient = useQueryClient();
- const [stateRefetchInterval, setStateRefetchInterval] = useState(
- SLO_SHORT_REFETCH_INTERVAL
- );
+
+ const { dataView } = useCreateDataView({
+ indexPatternString: SLO_SUMMARY_DESTINATION_INDEX_NAME,
+ });
+
+ const filters = useMemo(() => {
+ try {
+ return JSON.stringify(
+ buildQueryFromFilters(filterDSL, dataView, {
+ ignoreFilterIfFieldNotInIndex: true,
+ })
+ );
+ } catch (e) {
+ return '';
+ }
+ }, [filterDSL, dataView]);
const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
- queryKey: sloKeys.list({ kqlQuery, page, perPage, sortBy, sortDirection }),
+ queryKey: sloKeys.list({
+ kqlQuery,
+ page,
+ perPage,
+ sortBy,
+ sortDirection,
+ filters,
+ lastRefresh,
+ }),
queryFn: async ({ signal }) => {
- const response = await http.get(`/api/observability/slos`, {
+ return await http.get(`/api/observability/slos`, {
query: {
...(kqlQuery && { kqlQuery }),
...(sortBy && { sortBy }),
...(sortDirection && { sortDirection }),
...(page && { page }),
...(perPage && { perPage }),
+ ...(filters && { filters }),
},
signal,
});
-
- return response;
},
cacheTime: 0,
refetchOnWindowFocus: false,
- refetchInterval: shouldRefetch ? stateRefetchInterval : undefined,
retry: (failureCount, error) => {
if (String(error) === 'Error: Forbidden') {
return false;
@@ -79,16 +104,6 @@ export function useFetchSloList({
queryClient.invalidateQueries({ queryKey: sloKeys.historicalSummaries(), exact: false });
queryClient.invalidateQueries({ queryKey: sloKeys.activeAlerts(), exact: false });
queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false });
-
- if (!shouldRefetch) {
- return;
- }
-
- if (results.find((slo) => slo.summary.status === 'NO_DATA' || !slo.summary)) {
- setStateRefetchInterval(SLO_SHORT_REFETCH_INTERVAL);
- } else {
- setStateRefetchInterval(SLO_LONG_REFETCH_INTERVAL);
- }
},
onError: (error: Error) => {
toasts.addError(error, {
diff --git a/x-pack/plugins/observability/public/locators/slo_list.test.ts b/x-pack/plugins/observability/public/locators/slo_list.test.ts
index 677e831134496..5eb537b2182a4 100644
--- a/x-pack/plugins/observability/public/locators/slo_list.test.ts
+++ b/x-pack/plugins/observability/public/locators/slo_list.test.ts
@@ -14,7 +14,7 @@ describe('SloListLocator', () => {
const location = await locator.getLocation({});
expect(location.app).toEqual('observability');
expect(location.path).toMatchInlineSnapshot(
- `"/slos?search=(compact:!t,kqlQuery:'',page:0,perPage:25,sort:(by:status,direction:desc),view:cardView)"`
+ `"/slos?search=(compact:!t,filters:!(),kqlQuery:'',lastRefresh:0,page:0,perPage:25,sort:(by:status,direction:desc),view:cardView)"`
);
});
@@ -24,7 +24,7 @@ describe('SloListLocator', () => {
});
expect(location.app).toEqual('observability');
expect(location.path).toMatchInlineSnapshot(
- `"/slos?search=(compact:!t,kqlQuery:'slo.name:%20%22Service%20Availability%22%20and%20slo.indicator.type%20:%20%22sli.kql.custom%22',page:0,perPage:25,sort:(by:status,direction:desc),view:cardView)"`
+ `"/slos?search=(compact:!t,filters:!(),kqlQuery:'slo.name:%20%22Service%20Availability%22%20and%20slo.indicator.type%20:%20%22sli.kql.custom%22',lastRefresh:0,page:0,perPage:25,sort:(by:status,direction:desc),view:cardView)"`
);
});
});
diff --git a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx
index b57c512565fc1..be167785e2bad 100644
--- a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx
+++ b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx
@@ -12,6 +12,7 @@ import React from 'react';
import { useKibana } from '../../../../utils/kibana_react';
import { usePluginContext } from '../../../../hooks/use_plugin_context';
import HeaderMenuPortal from './header_menu_portal';
+const SLO_FEEDBACK_LINK = 'https://ela.st/slo-feedback';
export function HeaderMenu(): React.ReactElement | null {
const {
@@ -27,6 +28,16 @@ export function HeaderMenu(): React.ReactElement | null {
return (
+
+ {i18n.translate('xpack.observability.slo.giveFeedback', {
+ defaultMessage: 'Give feedback',
+ })}
+
,
- ,
],
bottomBorder: false,
}}
diff --git a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx
index 7a26fc117cc7a..052ef26cd758b 100644
--- a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx
@@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n';
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';
import { createHtmlPortalNode, OutPortal } from 'react-reverse-portal';
+import { FeedbackButton } from '../alert_details/components/feedback_button';
import { paths } from '../../../common/locators/paths';
import { useKibana } from '../../utils/kibana_react';
import { usePluginContext } from '../../hooks/use_plugin_context';
@@ -18,7 +19,6 @@ import { useFetchSloDetails } from '../../hooks/slo/use_fetch_slo_details';
import { useLicense } from '../../hooks/use_license';
import { useCapabilities } from '../../hooks/slo/use_capabilities';
import { useFetchSloGlobalDiagnosis } from '../../hooks/slo/use_fetch_global_diagnosis';
-import { FeedbackButton } from '../../components/slo/feedback_button/feedback_button';
import { SloEditForm } from './components/slo_edit_form';
import { HeaderMenu } from '../overview/components/header_menu/header_menu';
diff --git a/x-pack/plugins/observability/public/pages/slos/components/common/create_slo_btn.tsx b/x-pack/plugins/observability/public/pages/slos/components/common/create_slo_btn.tsx
new file mode 100644
index 0000000000000..1a71c82e23d3f
--- /dev/null
+++ b/x-pack/plugins/observability/public/pages/slos/components/common/create_slo_btn.tsx
@@ -0,0 +1,39 @@
+/*
+ * 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 } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+import { useKibana } from '../../../../utils/kibana_react';
+import { paths } from '../../../../../common/locators/paths';
+import { useCapabilities } from '../../../../hooks/slo/use_capabilities';
+
+export function CreateSloBtn() {
+ const {
+ application: { navigateToUrl },
+ http: { basePath },
+ } = useKibana().services;
+
+ const { hasWriteCapabilities } = useCapabilities();
+
+ const handleClickCreateSlo = () => {
+ navigateToUrl(basePath.prepend(paths.observability.sloCreate));
+ };
+ return (
+
+ {i18n.translate('xpack.observability.slo.sloList.pageHeader.create', {
+ defaultMessage: 'Create SLO',
+ })}
+
+ );
+}
diff --git a/x-pack/plugins/observability/public/pages/slos/components/common/sort_by_select.tsx b/x-pack/plugins/observability/public/pages/slos/components/common/sort_by_select.tsx
new file mode 100644
index 0000000000000..ac14034864395
--- /dev/null
+++ b/x-pack/plugins/observability/public/pages/slos/components/common/sort_by_select.tsx
@@ -0,0 +1,113 @@
+/*
+ * 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 {
+ EuiFilterButton,
+ EuiFilterGroup,
+ EuiPopover,
+ EuiPopoverTitle,
+ EuiSelectable,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import React, { useState } from 'react';
+import { SearchState } from '../../hooks/use_url_search_state';
+import { Item, SortField } from '../slo_list_search_bar';
+
+interface Props {
+ initialState: SearchState;
+ loading: boolean;
+ onStateChange: (newState: Partial) => void;
+}
+
+export function SortBySelect({ initialState, onStateChange, loading }: Props) {
+ const [isSortPopoverOpen, setSortPopoverOpen] = useState(false);
+ const [sortOptions, setSortOptions] = useState>>(
+ SORT_OPTIONS.map((option) => ({
+ ...option,
+ checked: option.type === initialState.sort.by ? 'on' : undefined,
+ }))
+ );
+
+ const selectedSort = sortOptions.find((option) => option.checked === 'on');
+
+ const handleToggleSortButton = () => setSortPopoverOpen(!isSortPopoverOpen);
+ const handleChangeSort = (newOptions: Array- >) => {
+ setSortOptions(newOptions);
+ setSortPopoverOpen(false);
+ onStateChange({
+ page: 0,
+ sort: { by: newOptions.find((o) => o.checked)!.type, direction: initialState.sort.direction },
+ });
+ };
+
+ return (
+
+
+ {i18n.translate('xpack.observability.slo.list.sortByType', {
+ defaultMessage: 'Sort by {type}',
+ values: { type: selectedSort?.label.toLowerCase() ?? '' },
+ })}
+
+ }
+ isOpen={isSortPopoverOpen}
+ closePopover={handleToggleSortButton}
+ panelPaddingSize="none"
+ anchorPosition="downCenter"
+ >
+
+
+ {i18n.translate('xpack.observability.slo.list.sortBy', {
+ defaultMessage: 'Sort by',
+ })}
+
+ >
+ singleSelection="always"
+ options={sortOptions}
+ onChange={handleChangeSort}
+ isLoading={loading}
+ >
+ {(list) => list}
+
+
+
+
+ );
+}
+
+const SORT_OPTIONS: Array- > = [
+ {
+ label: i18n.translate('xpack.observability.slo.list.sortBy.sliValue', {
+ defaultMessage: 'SLI value',
+ }),
+ type: 'sli_value',
+ },
+ {
+ label: i18n.translate('xpack.observability.slo.list.sortBy.sloStatus', {
+ defaultMessage: 'SLO status',
+ }),
+ type: 'status',
+ },
+ {
+ label: i18n.translate('xpack.observability.slo.list.sortBy.errorBudgetConsumed', {
+ defaultMessage: 'Error budget consumed',
+ }),
+ type: 'error_budget_consumed',
+ },
+ {
+ label: i18n.translate('xpack.observability.slo.list.sortBy.errorBudgetRemaining', {
+ defaultMessage: 'Error budget remaining',
+ }),
+ type: 'error_budget_remaining',
+ },
+];
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list.stories.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list.stories.tsx
index 244bda63596b7..3e6dd1c87d798 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list.stories.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list.stories.tsx
@@ -9,7 +9,7 @@ import React from 'react';
import { ComponentStory } from '@storybook/react';
import { KibanaReactStorybookDecorator } from '../../../utils/kibana_react.storybook_decorator';
-import { SloList as Component, Props } from './slo_list';
+import { SloList as Component } from './slo_list';
export default {
component: Component,
@@ -18,11 +18,9 @@ export default {
decorators: [KibanaReactStorybookDecorator],
};
-const Template: ComponentStory = (props: Props) => ;
+const Template: ComponentStory = () => ;
-const defaultProps = {
- autoRefresh: true,
-};
+const defaultProps = {};
export const SloList = Template.bind({});
SloList.args = defaultProps;
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx
index a25aae4afd4f9..893f866b3990b 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx
@@ -7,26 +7,17 @@
import { EuiFlexGroup, EuiFlexItem, EuiTablePagination } from '@elastic/eui';
import { useIsMutating } from '@tanstack/react-query';
-import React, { useState } from 'react';
+import React from 'react';
+import { CreateSloBtn } from './common/create_slo_btn';
import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list';
-import { useUrlSearchState } from '../hooks/use_url_search_state';
+import { SearchState, useUrlSearchState } from '../hooks/use_url_search_state';
import { SlosView } from './slos_view';
-import { SloListSearchBar, SortDirection, SortField } from './slo_list_search_bar';
-import { SLOView, ToggleSLOView } from './toggle_slo_view';
+import { SloListSearchBar } from './slo_list_search_bar';
+import { ToggleSLOView } from './toggle_slo_view';
-export interface Props {
- autoRefresh: boolean;
-}
-
-export function SloList({ autoRefresh }: Props) {
+export function SloList() {
const { state, store: storeState } = useUrlSearchState();
- const [page, setPage] = useState(state.page);
- const [perPage, setPerPage] = useState(state.perPage);
- const [query, setQuery] = useState(state.kqlQuery);
- const [sort, setSort] = useState(state.sort.by);
- const [direction] = useState(state.sort.direction);
- const [view, setView] = useState(state.view);
- const [isCompact, setCompact] = useState(state.compact);
+ const { view, page, perPage, kqlQuery, filters, compact: isCompact } = state;
const {
isLoading,
@@ -35,11 +26,12 @@ export function SloList({ autoRefresh }: Props) {
data: sloList,
} = useFetchSloList({
perPage,
+ filters,
page: page + 1,
- kqlQuery: query,
- sortBy: sort,
- sortDirection: direction,
- shouldRefetch: autoRefresh,
+ kqlQuery,
+ sortBy: state.sort.by,
+ sortDirection: state.sort.direction,
+ lastRefresh: state.lastRefresh,
});
const { results = [], total = 0 } = sloList ?? {};
@@ -49,49 +41,34 @@ export function SloList({ autoRefresh }: Props) {
const isUpdatingSlo = Boolean(useIsMutating(['updatingSlo']));
const isDeletingSlo = Boolean(useIsMutating(['deleteSlo']));
- const handlePageClick = (pageNumber: number) => {
- setPage(pageNumber);
- storeState({ page: pageNumber });
- };
-
- const handleChangeQuery = (newQuery: string) => {
- setPage(0);
- setQuery(newQuery);
- storeState({ page: 0, kqlQuery: newQuery });
- };
-
- const handleChangeSort = (newSort: SortField) => {
- setPage(0);
- setSort(newSort);
- storeState({ page: 0, sort: { by: newSort, direction: state.sort.direction } });
- };
-
- const handleChangeView = (newView: SLOView) => {
- setView(newView);
- storeState({ view: newView });
- };
-
- const handleToggleCompactView = () => {
- const newCompact = !isCompact;
- setCompact(newCompact);
- storeState({ compact: newCompact });
+ const onStateChange = (newState: Partial) => {
+ storeState({ page: 0, ...newState });
};
return (
-
+
+
+
+
+
+
+
+
onStateChange({ view: newView })}
+ onToggleCompactView={() => onStateChange({ compact: !isCompact })}
isCompact={isCompact}
/>
@@ -108,12 +85,13 @@ export function SloList({ autoRefresh }: Props) {
{
+ onStateChange({ page: newPage });
+ }}
itemsPerPage={perPage}
itemsPerPageOptions={[10, 25, 50, 100]}
onChangeItemsPerPage={(newPerPage) => {
- setPerPage(newPerPage);
- storeState({ perPage: newPerPage });
+ storeState({ perPage: newPerPage, page: 0 });
}}
/>
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.stories.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.stories.tsx
index fb39f46e81e96..fbf2afa253c7c 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.stories.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.stories.tsx
@@ -22,8 +22,7 @@ const Template: ComponentStory = (props: Props) => {},
- onChangeSort: () => {},
+ onStateChange: () => {},
initialState: DEFAULT_STATE,
};
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.tsx
index c1f08ca69fd9d..df9593d99e2eb 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_search_bar.tsx
@@ -5,29 +5,25 @@
* 2.0.
*/
-import {
- EuiFilterButton,
- EuiFilterGroup,
- EuiFlexGroup,
- EuiFlexItem,
- EuiPopover,
- EuiPopoverTitle,
- EuiSelectable,
- EuiSelectableOption,
-} from '@elastic/eui';
+import { EuiSelectableOption } from '@elastic/eui';
import { EuiSelectableOptionCheckedType } from '@elastic/eui/src/components/selectable/selectable_option';
-import { Query } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
-import React, { useState } from 'react';
-import { useCreateDataView } from '../../../hooks/use_create_data_view';
+import React from 'react';
+import { Filter } from '@kbn/es-query';
+import styled from 'styled-components';
import { useKibana } from '../../../utils/kibana_react';
+import { ObservabilityPublicPluginsStart } from '../../..';
+import { SortBySelect } from './common/sort_by_select';
+import { SLO_SUMMARY_DESTINATION_INDEX_NAME } from '../../../../common/slo/constants';
+import { useCreateDataView } from '../../../hooks/use_create_data_view';
import { SearchState } from '../hooks/use_url_search_state';
export interface Props {
+ query?: string;
+ filters?: Filter[];
loading: boolean;
initialState: SearchState;
- onChangeQuery: (query: string) => void;
- onChangeSort: (sort: SortField) => void;
+ onStateChange: (newState: Partial) => void;
}
export type SortField = 'sli_value' | 'error_budget_consumed' | 'error_budget_remaining' | 'status';
@@ -39,127 +35,54 @@ export type Item = EuiSelectableOption & {
checked?: EuiSelectableOptionCheckedType;
};
-const SORT_OPTIONS: Array
- > = [
- {
- label: i18n.translate('xpack.observability.slo.list.sortBy.sliValue', {
- defaultMessage: 'SLI value',
- }),
- type: 'sli_value',
- },
- {
- label: i18n.translate('xpack.observability.slo.list.sortBy.sloStatus', {
- defaultMessage: 'SLO status',
- }),
- type: 'status',
- },
- {
- label: i18n.translate('xpack.observability.slo.list.sortBy.errorBudgetConsumed', {
- defaultMessage: 'Error budget consumed',
- }),
- type: 'error_budget_consumed',
- },
- {
- label: i18n.translate('xpack.observability.slo.list.sortBy.errorBudgetRemaining', {
- defaultMessage: 'Error budget remaining',
- }),
- type: 'error_budget_remaining',
- },
-];
-
export type ViewMode = 'default' | 'compact';
-export function SloListSearchBar({ loading, onChangeQuery, onChangeSort, initialState }: Props) {
+export function SloListSearchBar({ query, filters, loading, initialState, onStateChange }: Props) {
+ const { dataView } = useCreateDataView({
+ indexPatternString: SLO_SUMMARY_DESTINATION_INDEX_NAME,
+ });
+
const {
unifiedSearch: {
- ui: { QueryStringInput },
+ ui: { SearchBar },
},
- } = useKibana().services;
- const { dataView } = useCreateDataView({ indexPatternString: '.slo-observability.summary-*' });
-
- const [query, setQuery] = useState(initialState.kqlQuery);
- const [isSortPopoverOpen, setSortPopoverOpen] = useState(false);
- const [sortOptions, setSortOptions] = useState>>(
- SORT_OPTIONS.map((option) => ({
- ...option,
- checked: option.type === initialState.sort.by ? 'on' : undefined,
- }))
- );
- const selectedSort = sortOptions.find((option) => option.checked === 'on');
-
- const handleToggleSortButton = () => setSortPopoverOpen(!isSortPopoverOpen);
- const handleChangeSort = (newOptions: Array
- >) => {
- setSortOptions(newOptions);
- setSortPopoverOpen(false);
- onChangeSort(newOptions.find((o) => o.checked)!.type);
- };
+ } = useKibana().services;
return (
-
-
- {
- setQuery(String(value.query));
- onChangeQuery(String(value.query));
- }}
- disableLanguageSwitcher
- isDisabled={loading}
- autoSubmit
- indexPatterns={dataView ? [dataView] : []}
- placeholder={i18n.translate('xpack.observability.slo.list.search', {
- defaultMessage: 'Search your SLOs...',
- })}
- query={{ query: String(query), language: 'kuery' }}
- size="s"
- onChange={(value) => setQuery(String(value.query))}
- />
-
-
-
-
-
-
-
- {i18n.translate('xpack.observability.slo.list.sortByType', {
- defaultMessage: 'Sort by {type}',
- values: { type: selectedSort?.label.toLowerCase() ?? '' },
- })}
-
- }
- isOpen={isSortPopoverOpen}
- closePopover={handleToggleSortButton}
- panelPaddingSize="none"
- anchorPosition="downCenter"
- >
-
-
- {i18n.translate('xpack.observability.slo.list.sortBy', {
- defaultMessage: 'Sort by',
- })}
-
- >
- singleSelection="always"
- options={sortOptions}
- onChange={handleChangeSort}
- isLoading={loading}
- >
- {(list) => list}
-
-
-
-
-
-
-
-
+
+ (
+
+ )}
+ filters={filters}
+ onFiltersUpdated={(newFilters) => {
+ onStateChange({ filters: newFilters });
+ }}
+ onQuerySubmit={({ query: value }) => {
+ onStateChange({ kqlQuery: String(value?.query), lastRefresh: Date.now() });
+ }}
+ query={{ query: String(query), language: 'kuery' }}
+ showSubmitButton={true}
+ showDatePicker={false}
+ showQueryInput={true}
+ disableQueryLanguageSwitcher={true}
+ />
+
);
}
+
+const Container = styled.div`
+ .uniSearchBar {
+ padding: 0;
+ }
+`;
diff --git a/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx
index e5881e8f1ff4c..15d376f1f0d10 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx
@@ -7,7 +7,9 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
-import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n-react';
+import { FindSLOResponse } from '@kbn/slo-schema';
import { SLOViewSettings } from './slo_view_settings';
export type SLOView = 'cardView' | 'listView';
@@ -17,6 +19,7 @@ interface Props {
onChangeView: (view: SLOView) => void;
isCompact: boolean;
sloView: SLOView;
+ sloList?: FindSLOResponse;
}
const toggleButtonsIcons = [
@@ -39,10 +42,38 @@ export function ToggleSLOView({
onChangeView,
onToggleCompactView,
isCompact = true,
+ sloList,
}: Props) {
+ const total = sloList?.total ?? 0;
+ const pageSize = sloList?.perPage ?? 0;
+ const pageIndex = sloList?.page ?? 1;
+
+ const rangeStart = (total === 0 ? 0 : pageSize * (pageIndex - 1)) + 1;
+ const rangeEnd = Math.min(total, pageSize * (pageIndex - 1) + pageSize);
+
return (
-
+
+
+
+
+
) => Promise;
} {
+ const [state, setState] = useState(DEFAULT_STATE);
const history = useHistory();
- const urlStateStorage = createKbnUrlStateStorage({
- history,
- useHash: false,
- useHashQuery: false,
- });
+ const urlStateStorage = useRef(
+ createKbnUrlStateStorage({
+ history,
+ useHash: false,
+ useHashQuery: false,
+ })
+ );
- const searchState =
- urlStateStorage.get(SLO_LIST_SEARCH_URL_STORAGE_KEY) ?? DEFAULT_STATE;
+ useEffect(() => {
+ const sub = urlStateStorage.current
+ ?.change$(SLO_LIST_SEARCH_URL_STORAGE_KEY)
+ .subscribe((newSearchState) => {
+ if (newSearchState) {
+ setState(newSearchState);
+ }
+ });
+
+ setState(
+ urlStateStorage.current?.get(SLO_LIST_SEARCH_URL_STORAGE_KEY) ?? DEFAULT_STATE
+ );
+
+ return () => {
+ sub?.unsubscribe();
+ };
+ }, [urlStateStorage]);
return {
- state: deepmerge(DEFAULT_STATE, searchState),
- store: (state: Partial) =>
- urlStateStorage.set(SLO_LIST_SEARCH_URL_STORAGE_KEY, deepmerge(searchState, state), {
- replace: true,
- }),
+ state: deepmerge(DEFAULT_STATE, state),
+ store: (newState: Partial) =>
+ urlStateStorage.current?.set(
+ SLO_LIST_SEARCH_URL_STORAGE_KEY,
+ { ...state, ...newState },
+ {
+ replace: true,
+ }
+ ),
};
}
diff --git a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx
index 430a160515039..ca09a51af1464 100644
--- a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx
@@ -111,6 +111,7 @@ const mockKibana = () => {
},
unifiedSearch: {
ui: {
+ SearchBar: () => SearchBar
,
QueryStringInput: () => Query String Input
,
},
autocomplete: {
@@ -181,22 +182,7 @@ describe('SLOs Page', () => {
render();
});
- expect(screen.getByText('Create new SLO')).toBeTruthy();
- });
-
- it('should have an Auto Refresh button', async () => {
- useFetchSloListMock.mockReturnValue({ isLoading: false, data: sloList });
-
- useFetchHistoricalSummaryMock.mockReturnValue({
- isLoading: false,
- data: historicalSummaryData,
- });
-
- await act(async () => {
- render();
- });
-
- expect(screen.getByTestId('autoRefreshButton')).toBeTruthy();
+ expect(screen.getByText('Create SLO')).toBeTruthy();
});
describe('when API has returned results', () => {
@@ -218,7 +204,7 @@ describe('SLOs Page', () => {
expect(screen.queryByTestId('slosPage')).toBeTruthy();
expect(screen.queryByTestId('sloList')).toBeTruthy();
expect(screen.queryAllByTestId('sloItem')).toBeTruthy();
- expect(screen.queryAllByTestId('sloItem').length).toBe(sloList.results.length);
+ expect((await screen.findAllByTestId('sloItem')).length).toBe(sloList.results.length);
});
it('allows editing an SLO', async () => {
diff --git a/x-pack/plugins/observability/public/pages/slos/slos.tsx b/x-pack/plugins/observability/public/pages/slos/slos.tsx
index 4ea3f27fade3c..931ab7885b8ac 100644
--- a/x-pack/plugins/observability/public/pages/slos/slos.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/slos.tsx
@@ -5,22 +5,16 @@
* 2.0.
*/
-import React, { useEffect, useState } from 'react';
-import { EuiButton, EuiSpacer } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
+import React, { useEffect } from 'react';
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';
+import { i18n } from '@kbn/i18n';
import { useKibana } from '../../utils/kibana_react';
import { usePluginContext } from '../../hooks/use_plugin_context';
import { useLicense } from '../../hooks/use_license';
-import { useCapabilities } from '../../hooks/slo/use_capabilities';
import { useFetchSloList } from '../../hooks/slo/use_fetch_slo_list';
import { SloList } from './components/slo_list';
-import { AutoRefreshButton } from '../../components/slo/auto_refresh_button';
-import { HeaderTitle } from './components/header_title';
-import { FeedbackButton } from '../../components/slo/feedback_button/feedback_button';
import { paths } from '../../../common/locators/paths';
-import { useAutoRefreshStorage } from '../../components/slo/auto_refresh_button/hooks/use_auto_refresh_storage';
import { HeaderMenu } from '../overview/components/header_menu/header_menu';
import { SloOutdatedCallout } from '../../components/slo/slo_outdated_callout';
@@ -30,15 +24,11 @@ export function SlosPage() {
http: { basePath },
} = useKibana().services;
const { ObservabilityPageTemplate } = usePluginContext();
- const { hasWriteCapabilities } = useCapabilities();
const { hasAtLeast } = useLicense();
const { isLoading, isError, data: sloList } = useFetchSloList();
const { total } = sloList ?? { total: 0 };
- const { storeAutoRefreshState, getAutoRefreshState } = useAutoRefreshStorage();
- const [isAutoRefreshing, setIsAutoRefreshing] = useState(getAutoRefreshState());
-
useBreadcrumbs([
{
href: basePath.prepend(paths.observability.slos),
@@ -55,45 +45,11 @@ export function SlosPage() {
}
}, [basePath, hasAtLeast, isError, isLoading, navigateToUrl, total]);
- const handleClickCreateSlo = () => {
- navigateToUrl(basePath.prepend(paths.observability.sloCreate));
- };
-
- const handleToggleAutoRefresh = () => {
- setIsAutoRefreshing(!isAutoRefreshing);
- storeAutoRefreshState(!isAutoRefreshing);
- };
-
return (
- ,
- rightSideItems: [
-
- {i18n.translate('xpack.observability.slo.sloList.pageHeader.createNewButtonLabel', {
- defaultMessage: 'Create new SLO',
- })}
- ,
- ,
- ,
- ],
- bottomBorder: false,
- }}
- data-test-subj="slosPage"
- >
+
-
-
+
);
}
diff --git a/x-pack/plugins/observability/server/services/slo/find_slo.test.ts b/x-pack/plugins/observability/server/services/slo/find_slo.test.ts
index e8d80ef8e74f5..396f026b936b3 100644
--- a/x-pack/plugins/observability/server/services/slo/find_slo.test.ts
+++ b/x-pack/plugins/observability/server/services/slo/find_slo.test.ts
@@ -35,6 +35,7 @@ describe('FindSLO', () => {
expect(mockSummarySearchClient.search.mock.calls[0]).toMatchInlineSnapshot(`
Array [
+ "",
"",
Object {
"direction": "asc",
@@ -128,6 +129,7 @@ describe('FindSLO', () => {
expect(mockSummarySearchClient.search.mock.calls[0]).toMatchInlineSnapshot(`
Array [
"slo.name:'Service*' and slo.indicator.type:'sli.kql.custom'",
+ "",
Object {
"direction": "asc",
"field": "error_budget_consumed",
diff --git a/x-pack/plugins/observability/server/services/slo/find_slo.ts b/x-pack/plugins/observability/server/services/slo/find_slo.ts
index fb90ec86d04d5..690d61a30c260 100644
--- a/x-pack/plugins/observability/server/services/slo/find_slo.ts
+++ b/x-pack/plugins/observability/server/services/slo/find_slo.ts
@@ -24,6 +24,7 @@ export class FindSLO {
public async execute(params: FindSLOParams): Promise {
const sloSummaryList = await this.summarySearchClient.search(
params.kqlQuery ?? '',
+ params.filters ?? '',
toSort(params),
toPagination(params)
);
diff --git a/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts b/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts
index 256aa9164ea3b..3743cbea46e06 100644
--- a/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts
+++ b/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts
@@ -36,7 +36,7 @@ describe('Summary Search Client', () => {
it('returns an empty response on error', async () => {
esClientMock.count.mockRejectedValue(new Error('Cannot reach es'));
- await expect(service.search('', defaultSort, defaultPagination)).resolves
+ await expect(service.search('', '', defaultSort, defaultPagination)).resolves
.toMatchInlineSnapshot(`
Object {
"page": 1,
@@ -53,7 +53,7 @@ describe('Summary Search Client', () => {
_shards: { failed: 0, successful: 1, total: 1 },
});
- await expect(service.search('', defaultSort, defaultPagination)).resolves
+ await expect(service.search('', '', defaultSort, defaultPagination)).resolves
.toMatchInlineSnapshot(`
Object {
"page": 1,
@@ -99,7 +99,7 @@ describe('Summary Search Client', () => {
},
});
- const results = await service.search('', defaultSort, defaultPagination);
+ const results = await service.search('', '', defaultSort, defaultPagination);
expect(esClientMock.deleteByQuery).toHaveBeenCalled();
expect(esClientMock.deleteByQuery.mock.calls[0]).toMatchSnapshot();
diff --git a/x-pack/plugins/observability/server/services/slo/summary_search_client.ts b/x-pack/plugins/observability/server/services/slo/summary_search_client.ts
index 9715d727f6fc5..be52cb583802a 100644
--- a/x-pack/plugins/observability/server/services/slo/summary_search_client.ts
+++ b/x-pack/plugins/observability/server/services/slo/summary_search_client.ts
@@ -44,7 +44,12 @@ export interface Sort {
}
export interface SummarySearchClient {
- search(kqlQuery: string, sort: Sort, pagination: Pagination): Promise>;
+ search(
+ kqlQuery: string,
+ filters: string,
+ sort: Sort,
+ pagination: Pagination
+ ): Promise>;
}
export class DefaultSummarySearchClient implements SummarySearchClient {
@@ -56,16 +61,29 @@ export class DefaultSummarySearchClient implements SummarySearchClient {
async search(
kqlQuery: string,
+ filters: string,
sort: Sort,
pagination: Pagination
): Promise> {
+ let parsedFilters: any = {};
+
+ try {
+ parsedFilters = JSON.parse(filters);
+ } catch (e) {
+ this.logger.error(`Failed to parse filters: ${e.message}`);
+ }
+
try {
const summarySearch = await this.esClient.search({
index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
track_total_hits: true,
query: {
bool: {
- filter: [{ term: { spaceId: this.spaceId } }, getElastichsearchQueryOrThrow(kqlQuery)],
+ filter: [
+ { term: { spaceId: this.spaceId } },
+ getElastichsearchQueryOrThrow(kqlQuery),
+ ...(parsedFilters.filter ?? []),
+ ],
},
},
sort: {
diff --git a/x-pack/plugins/observability_shared/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/observability_shared/public/hooks/use_breadcrumbs.ts
index 53f1c1f4e02ab..18a08f59db249 100644
--- a/x-pack/plugins/observability_shared/public/hooks/use_breadcrumbs.ts
+++ b/x-pack/plugins/observability_shared/public/hooks/use_breadcrumbs.ts
@@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
import { ApplicationStart, ChromeBreadcrumb, ChromeStart } from '@kbn/core/public';
import { MouseEvent, useEffect } from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
+import { ChromeBreadcrumbsAppendExtension } from '@kbn/core-chrome-browser';
import { useQueryParams } from './use_query_params';
function addClickHandlers(
@@ -36,13 +37,14 @@ function getTitleFromBreadCrumbs(breadcrumbs: ChromeBreadcrumb[]) {
export const useBreadcrumbs = (
extraCrumbs: ChromeBreadcrumb[],
- app?: { id: string; label: string }
+ app?: { id: string; label: string },
+ breadcrumbsAppendExtension?: ChromeBreadcrumbsAppendExtension
) => {
const params = useQueryParams();
const {
services: {
- chrome: { docTitle, setBreadcrumbs },
+ chrome: { docTitle, setBreadcrumbs, setBreadcrumbsAppendExtension },
application: { getUrlForApp, navigateToUrl },
},
} = useKibana<{
@@ -52,6 +54,17 @@ export const useBreadcrumbs = (
const setTitle = docTitle.change;
const appPath = getUrlForApp(app?.id ?? 'observability-overview') ?? '';
+ useEffect(() => {
+ if (breadcrumbsAppendExtension) {
+ setBreadcrumbsAppendExtension(breadcrumbsAppendExtension);
+ }
+ return () => {
+ if (breadcrumbsAppendExtension) {
+ setBreadcrumbsAppendExtension(undefined);
+ }
+ };
+ }, [breadcrumbsAppendExtension, setBreadcrumbsAppendExtension]);
+
useEffect(() => {
const breadcrumbs = [
{
diff --git a/x-pack/plugins/observability_shared/tsconfig.json b/x-pack/plugins/observability_shared/tsconfig.json
index 7a875f30e8736..b63bcf88c2df5 100644
--- a/x-pack/plugins/observability_shared/tsconfig.json
+++ b/x-pack/plugins/observability_shared/tsconfig.json
@@ -39,7 +39,8 @@
"@kbn/shared-ux-error-boundary",
"@kbn/management-settings-field-definition",
"@kbn/management-settings-types",
- "@kbn/management-settings-utilities"
+ "@kbn/management-settings-utilities",
+ "@kbn/core-chrome-browser"
],
"exclude": ["target/**/*"]
}
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 278c8191415e4..be3e8b9b14bad 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -29019,7 +29019,6 @@
"xpack.observability.slo.duration.minutely": "Par minute",
"xpack.observability.slo.duration.monthly": "Mensuel",
"xpack.observability.slo.duration.weekly": "Hebdomadaire",
- "xpack.observability.slo.feedbackButtonLabel": "Dites-nous ce que vous pensez !",
"xpack.observability.slo.globalDiagnosis.errorNotification": "Vous ne disposez pas des autorisations nécessaires pour utiliser cette fonctionnalité.",
"xpack.observability.slo.indicators.apmAvailability": "Disponibilité APM",
"xpack.observability.slo.indicators.apmLatency": "Latence APM",
@@ -29199,7 +29198,6 @@
"xpack.observability.slo.sloEdit.timeWindowDuration.tooltip": "La durée de la fenêtre temporelle utilisée pour calculer le SLO.",
"xpack.observability.slo.sloEdit.timeWindowType.label": "Fenêtre temporelle",
"xpack.observability.slo.sloEdit.timeWindowType.tooltip": "Choisissez entre une fenêtre glissante ou alignée sur le calendrier.",
- "xpack.observability.slo.sloList.pageHeader.createNewButtonLabel": "Créer un nouveau SLO",
"xpack.observability.slo.sloList.welcomePrompt.buttonLabel": "Créer un SLO",
"xpack.observability.slo.sloList.welcomePrompt.getStartedMessage": "Pour commencer, créez votre premier SLO.",
"xpack.observability.slo.sloList.welcomePrompt.learnMore": "Envie d'en savoir plus ?",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 23c6cf1ef7ad4..a2b9dbfe95c87 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -29020,7 +29020,6 @@
"xpack.observability.slo.duration.minutely": "毎分",
"xpack.observability.slo.duration.monthly": "月ごと",
"xpack.observability.slo.duration.weekly": "週ごと",
- "xpack.observability.slo.feedbackButtonLabel": "ご意見をお聞かせください。",
"xpack.observability.slo.globalDiagnosis.errorNotification": "この機能を使用する権限がありません。",
"xpack.observability.slo.indicators.apmAvailability": "APM可用性",
"xpack.observability.slo.indicators.apmLatency": "APMレイテンシ",
@@ -29200,7 +29199,6 @@
"xpack.observability.slo.sloEdit.timeWindowDuration.tooltip": "SLOを計算するために使用される時間枠期間。",
"xpack.observability.slo.sloEdit.timeWindowType.label": "時間枠",
"xpack.observability.slo.sloEdit.timeWindowType.tooltip": "ローリング時間枠とカレンダー時間枠のどちらかを選択します。",
- "xpack.observability.slo.sloList.pageHeader.createNewButtonLabel": "新規SLOを作成",
"xpack.observability.slo.sloList.welcomePrompt.buttonLabel": "SLOの作成",
"xpack.observability.slo.sloList.welcomePrompt.getStartedMessage": "開始するには、まずSLOを作成します。",
"xpack.observability.slo.sloList.welcomePrompt.learnMore": "詳細について",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 3bb3a386b626f..54261e08bc1e8 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -29004,7 +29004,6 @@
"xpack.observability.slo.duration.minutely": "每分钟",
"xpack.observability.slo.duration.monthly": "每月",
"xpack.observability.slo.duration.weekly": "每周",
- "xpack.observability.slo.feedbackButtonLabel": "告诉我们您的看法!",
"xpack.observability.slo.globalDiagnosis.errorNotification": "您没有适当权限,无法使用此功能。",
"xpack.observability.slo.indicators.apmAvailability": "APM 可用性",
"xpack.observability.slo.indicators.apmLatency": "APM 延迟",
@@ -29184,7 +29183,6 @@
"xpack.observability.slo.sloEdit.timeWindowDuration.tooltip": "用于在其间计算 SLO 的时间窗口持续时间。",
"xpack.observability.slo.sloEdit.timeWindowType.label": "时间窗口",
"xpack.observability.slo.sloEdit.timeWindowType.tooltip": "选择滚动或日历对齐窗口。",
- "xpack.observability.slo.sloList.pageHeader.createNewButtonLabel": "创建新 SLO",
"xpack.observability.slo.sloList.welcomePrompt.buttonLabel": "创建 SLO",
"xpack.observability.slo.sloList.welcomePrompt.getStartedMessage": "要开始使用,请创建您的首个 SLO。",
"xpack.observability.slo.sloList.welcomePrompt.learnMore": "希望了解详情?",