mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[SLOs] Add/edit form show tags suggestions (#181075)
## Summary
Show tags as suggestions from existing SLOs
<img width="1194" alt="image"
src="12699ed3
-ff26-436d-a63f-a3b9422a1cfc">
This commit is contained in:
parent
ef5af17233
commit
d3207ec1ec
6 changed files with 130 additions and 2 deletions
|
@ -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<typeof getSLOSuggestionsResponseSchema>;
|
||||
|
||||
export { getSLOSuggestionsResponseSchema };
|
||||
export type { GetSLOSuggestionsResponse };
|
|
@ -20,3 +20,4 @@ export * from './manage';
|
|||
export * from './delete_instance';
|
||||
export * from './fetch_historical_summary';
|
||||
export * from './put_settings';
|
||||
export * from './get_suggestions';
|
||||
|
|
|
@ -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 (
|
||||
<EuiPanel
|
||||
hasBorder={false}
|
||||
|
@ -121,8 +124,7 @@ export function SloEditFormDescriptionSection() {
|
|||
defaultMessage: 'Add tags',
|
||||
})}
|
||||
isInvalid={fieldState.invalid}
|
||||
options={[]}
|
||||
noSuggestions
|
||||
options={suggestions?.tags ?? []}
|
||||
selectedOptions={generateTagOptions(field.value)}
|
||||
onChange={(selected: EuiComboBoxOptionOption[]) => {
|
||||
if (selected.length) {
|
||||
|
|
|
@ -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<GetSLOSuggestionsResponse>(
|
||||
'/internal/api/observability/slos/suggestions',
|
||||
{
|
||||
signal,
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
// ignore error
|
||||
}
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
keepPreviousData: true,
|
||||
});
|
||||
|
||||
return {
|
||||
suggestions: data,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
};
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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<GetSLOSuggestionsResponse> {
|
||||
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,
|
||||
})) ?? [],
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue