From d3207ec1ec0fb9b6cc43dedf0544e85bf4f90a48 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 18 Apr 2024 15:46:28 +0200 Subject: [PATCH] [SLOs] Add/edit form show tags suggestions (#181075) ## Summary Show tags as suggestions from existing SLOs image --- .../src/rest_specs/routes/get_suggestions.ts | 22 +++++++++ .../src/rest_specs/routes/index.ts | 1 + .../slo_edit_form_description_section.tsx | 6 ++- .../slo_edit/hooks/use_fetch_suggestions.ts | 39 +++++++++++++++ .../slo/server/routes/slo/route.ts | 17 +++++++ .../server/services/get_slo_suggestions.ts | 47 +++++++++++++++++++ 6 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_suggestions.ts create mode 100644 x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts create mode 100644 x-pack/plugins/observability_solution/slo/server/services/get_slo_suggestions.ts diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_suggestions.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_suggestions.ts new file mode 100644 index 0000000000000..b67fa9aba17f1 --- /dev/null +++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_suggestions.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import * as t from 'io-ts'; + +const getSLOSuggestionsResponseSchema = t.type({ + tags: t.array( + t.type({ + label: t.string, + value: t.string, + count: t.number, + }) + ), +}); + +type GetSLOSuggestionsResponse = t.OutputOf; + +export { getSLOSuggestionsResponseSchema }; +export type { GetSLOSuggestionsResponse }; diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/index.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/index.ts index afa90877253e3..57058d03790bb 100644 --- a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/index.ts +++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/index.ts @@ -20,3 +20,4 @@ export * from './manage'; export * from './delete_instance'; export * from './fetch_historical_summary'; export * from './put_settings'; +export * from './get_suggestions'; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx index 0e9af3602b9db..a210021674f6b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx @@ -19,6 +19,7 @@ import { import { i18n } from '@kbn/i18n'; import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; +import { useFetchSLOSuggestions } from '../hooks/use_fetch_suggestions'; import { OptionalText } from './common/optional_text'; import { CreateSLOForm } from '../types'; import { maxWidth } from './slo_edit_form'; @@ -29,6 +30,8 @@ export function SloEditFormDescriptionSection() { const descriptionId = useGeneratedHtmlId({ prefix: 'sloDescription' }); const tagsId = useGeneratedHtmlId({ prefix: 'tags' }); + const { suggestions } = useFetchSLOSuggestions(); + return ( { if (selected.length) { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts new file mode 100644 index 0000000000000..7e66bc954f23c --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts @@ -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 { useQuery } from '@tanstack/react-query'; +import { GetSLOSuggestionsResponse } from '@kbn/slo-schema'; +import { useKibana } from '../../../utils/kibana_react'; + +export function useFetchSLOSuggestions() { + const { http } = useKibana().services; + + const { isLoading, isError, isSuccess, data } = useQuery({ + queryKey: ['fetchSLOSuggestions'], + queryFn: async ({ signal }) => { + try { + return await http.get( + '/internal/api/observability/slos/suggestions', + { + signal, + } + ); + } catch (error) { + // ignore error + } + }, + refetchOnWindowFocus: false, + keepPreviousData: true, + }); + + return { + suggestions: data, + isLoading, + isSuccess, + isError, + }; +} diff --git a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts index 10b9ebe0d0ae6..80a9a18542da9 100644 --- a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts +++ b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts @@ -24,6 +24,7 @@ import { resetSLOParamsSchema, updateSLOParamsSchema, } from '@kbn/slo-schema'; +import { GetSLOSuggestions } from '../../services/get_slo_suggestions'; import type { IndicatorTypes } from '../../domain/models'; import { CreateSLO, @@ -445,6 +446,21 @@ const findSLOGroupsRoute = createSloServerRoute({ }, }); +const getSLOSuggestionsRoute = createSloServerRoute({ + endpoint: 'GET /internal/api/observability/slos/suggestions', + options: { + tags: ['access:slo_read'], + access: 'internal', + }, + handler: async ({ context }) => { + await assertPlatinumLicense(context); + + const soClient = (await context.core).savedObjects.client; + const getSLOSuggestions = new GetSLOSuggestions(soClient); + return await getSLOSuggestions.execute(); + }, +}); + const deleteSloInstancesRoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos/_delete_instances 2023-10-31', options: { @@ -642,4 +658,5 @@ export const sloRouteRepository = { ...getSLOInstancesRoute, ...resetSLORoute, ...findSLOGroupsRoute, + ...getSLOSuggestionsRoute, }; diff --git a/x-pack/plugins/observability_solution/slo/server/services/get_slo_suggestions.ts b/x-pack/plugins/observability_solution/slo/server/services/get_slo_suggestions.ts new file mode 100644 index 0000000000000..a9dfef5a14aa1 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/server/services/get_slo_suggestions.ts @@ -0,0 +1,47 @@ +/* + * 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 { SavedObjectsClientContract } from '@kbn/core/server'; +import { GetSLOSuggestionsResponse } from '@kbn/slo-schema'; +import { SO_SLO_TYPE } from '../saved_objects'; +type Buckets = Array<{ + key: string; + doc_count: number; +}>; + +interface AggsResponse { + tagsAggs: { + buckets: Buckets; + }; +} +export class GetSLOSuggestions { + constructor(private soClient: SavedObjectsClientContract) {} + + public async execute(): Promise { + const findResponse = await this.soClient.find({ + type: SO_SLO_TYPE, + perPage: 0, + aggs: { + tagsAggs: { + terms: { + field: `${SO_SLO_TYPE}.attributes.tags`, + size: 10000, + }, + }, + }, + }); + const { tagsAggs } = (findResponse?.aggregations as AggsResponse) ?? {}; + + return { + tags: + tagsAggs?.buckets?.map(({ key, doc_count: count }) => ({ + label: key, + value: key, + count, + })) ?? [], + }; + } +}