Skip to content

Commit

Permalink
paginated api for groups
Browse files Browse the repository at this point in the history
  • Loading branch information
mgiota committed Jan 23, 2024
1 parent df7f967 commit 30706f8
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 107 deletions.
26 changes: 26 additions & 0 deletions x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ const findSLOParamsSchema = t.partial({
}),
});

const groupBySchema = t.literal('tags'); // TODO add t.union when the rest options will be added

const findSLOGroupsParamsSchema = t.partial({
query: t.partial({
page: t.string,
perPage: t.string,
groupBy: groupBySchema,
}),
});

const sloResponseSchema = t.intersection([
t.type({
id: sloIdSchema,
Expand Down Expand Up @@ -124,6 +134,8 @@ const sloWithSummaryResponseSchema = t.intersection([
t.type({ summary: summarySchema }),
]);

const sloGroupsResponseSchema = t.record(t.string, t.number);

const getSLOQuerySchema = t.partial({
query: t.partial({
instanceId: allOrAnyString,
Expand Down Expand Up @@ -176,6 +188,13 @@ const findSLOResponseSchema = t.type({
results: t.array(sloWithSummaryResponseSchema),
});

const findSLOGroupsResponseSchema = t.type({
page: t.number,
perPage: t.number,
total: t.number,
results: sloGroupsResponseSchema,
});

const deleteSLOInstancesParamsSchema = t.type({
body: t.type({ list: t.array(t.type({ sloId: sloIdSchema, instanceId: t.string })) }),
});
Expand Down Expand Up @@ -262,6 +281,9 @@ type UpdateSLOResponse = t.OutputOf<typeof updateSLOResponseSchema>;
type FindSLOParams = t.TypeOf<typeof findSLOParamsSchema.props.query>;
type FindSLOResponse = t.OutputOf<typeof findSLOResponseSchema>;

type FindSLOGroupsParams = t.TypeOf<typeof findSLOGroupsParamsSchema.props.query>;
type FindSLOGroupsResponse = t.OutputOf<typeof findSLOGroupsResponseSchema>;

type DeleteSLOInstancesInput = t.OutputOf<typeof deleteSLOInstancesParamsSchema.props.body>;
type DeleteSLOInstancesParams = t.TypeOf<typeof deleteSLOInstancesParamsSchema.props.body>;

Expand Down Expand Up @@ -298,6 +320,8 @@ export {
deleteSLOInstancesParamsSchema,
findSLOParamsSchema,
findSLOResponseSchema,
findSLOGroupsParamsSchema,
findSLOGroupsResponseSchema,
getPreviewDataParamsSchema,
getPreviewDataResponseSchema,
getSLOParamsSchema,
Expand Down Expand Up @@ -327,6 +351,8 @@ export type {
DeleteSLOInstancesParams,
FindSLOParams,
FindSLOResponse,
FindSLOGroupsParams,
FindSLOGroupsResponse,
GetPreviewDataParams,
GetPreviewDataResponse,
GetSLOParams,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/observability/common/slo/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const getSLOTransformId = (sloId: string, sloRevision: number) =>
`slo-${sloId}-${sloRevision}`;

export const DEFAULT_SLO_PAGE_SIZE = 25;
export const DEFAULT_SLO_GROUPS_PAGE_SIZE = 25;

export const getSLOSummaryTransformId = (sloId: string, sloRevision: number) =>
`slo-summary-${sloId}-${sloRevision}`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ interface SloListFilter {
lastRefresh?: number;
}

interface SloGroupListFilter {
page: number;
perPage: number;
}

export const sloKeys = {
all: ['slo'] as const,
lists: () => [...sloKeys.all, 'list'] as const,
list: (filters: SloListFilter) => [...sloKeys.lists(), filters] as const,
groups: () => [...sloKeys.all, 'groups'],
groups: (filters: SloGroupListFilter) => [...sloKeys.all, filters] as const,
details: () => [...sloKeys.all, 'details'] as const,
detail: (sloId?: string) => [...sloKeys.details(), sloId] as const,
rules: () => [...sloKeys.all, 'rules'] as const,
Expand Down
115 changes: 51 additions & 64 deletions x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,71 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
IEsSearchRequest,
IKibanaSearchResponse,
isRunningResponse,
} from '@kbn/data-plugin/common';
import type { ISearchStart } from '@kbn/data-plugin/public';
import { useQuery } from '@tanstack/react-query';
import { i18n } from '@kbn/i18n';
import { FindSLOGroupsResponse } from '@kbn/slo-schema';
import { useKibana } from '../../utils/kibana_react';
import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN } from '../../../common/slo/constants';
import { sloKeys } from './query_key_factory';
import { DEFAULT_SLO_GROUPS_PAGE_SIZE } from '../../../common/slo/constants';

interface Aggregation {
doc_count: number;
key: string;
interface SLOGroupsParams {
page?: number;
perPage?: number;
}

interface GroupAggregationsResponse {
aggregations: {
groupByTags: {
buckets: Aggregation[];
};
};
interface UseFetchSloGroupsResponse {
isLoading: boolean;
isRefetching: boolean;
isSuccess: boolean;
isError: boolean;
data: FindSLOGroupsResponse | undefined;
}

const createFetchAggregations = async (searchService: ISearchStart) => {
const search = async <TResponse>(): Promise<TResponse> => {
return new Promise((resolve, reject) => {
searchService
.search<IEsSearchRequest, IKibanaSearchResponse<TResponse>>({
params: {
index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
body: {
size: 0,
aggs: {
groupByTags: {
terms: {
field: 'slo.tags',
},
},
},
},
},
})
.subscribe({
next: (response) => {
if (!isRunningResponse(response)) {
resolve(response.rawResponse);
}
},
error: (requestError) => {
searchService.showError(requestError);
reject(requestError);
},
});
});
};
const { aggregations } = await search<GroupAggregationsResponse>();
return aggregations;
};

export function useFetchSloGroups() {
export function useFetchSloGroups({
page = 1,
perPage = DEFAULT_SLO_GROUPS_PAGE_SIZE,
}: SLOGroupsParams = {}): UseFetchSloGroupsResponse {
const {
data: { search: searchService },
http,
notifications: { toasts },
} = useKibana().services;

const { data, isLoading, isFetching } = useQuery({
queryKey: sloKeys.groups(),
queryFn: async () => {
const response = await createFetchAggregations(searchService);
return response.groupByTags.buckets.reduce((acc, bucket) => {
return { ...acc, [bucket.key]: bucket.doc_count ?? 0 };
}, {} as Record<string, number>);
const { data, isLoading, isSuccess, isError, isRefetching } = useQuery({
queryKey: sloKeys.groups({ page, perPage }),
queryFn: async ({ signal }) => {
const response = await http.get<FindSLOGroupsResponse>(
'/internal/api/observability/slos/_groups',
{
query: {
...(page && { page }),
...(perPage && { perPage }),
},
signal,
}
);
return response;
},
cacheTime: 0,
refetchOnWindowFocus: false,
retry: (failureCount, error) => {
if (String(error) === 'Error: Forbidden') {
return false;
}
return failureCount < 4;
},
onError: (error: Error) => {
toasts.addError(error, {
title: i18n.translate('xpack.observability.slo.groups.list.errorNotification', {
defaultMessage: 'Something went wrong while fetching SLO Groups',
}),
});
},
});

return {
data: data || {},
data,
isLoading,
isFetching,
isSuccess,
isError,
isRefetching,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function GroupListView({ isCompact, group, kqlQuery, sloView, sort, direc

return (
<EuiPanel>
<MemoEuiAccordion buttonContent={group} id={group} initialIsOpen={true}>
<MemoEuiAccordion buttonContent={group} id={group} initialIsOpen={false}>
<>
<SlosView
sloList={results}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import React from 'react';
import { EuiFlexItem, EuiTablePagination } from '@elastic/eui';
import React, { useState } from 'react';
import { GroupListView } from './group_list_view';
import { useFetchSloGroups } from '../../../../hooks/slo/use_fetch_slo_groups';
import type { SortDirection } from '../slo_list_search_bar';
import { DEFAULT_SLO_GROUPS_PAGE_SIZE } from '../../../../../common/slo/constants';

interface Props {
isCompact: boolean;
Expand All @@ -20,7 +22,13 @@ interface Props {
}

export function GroupView({ isCompact, kqlQuery, sloView, sort, direction }: Props) {
const { data, isLoading } = useFetchSloGroups();
const [page, setPage] = useState(0);
const [perPage, setPerPage] = useState(DEFAULT_SLO_GROUPS_PAGE_SIZE);
const { data, isLoading } = useFetchSloGroups({ perPage, page: page + 1 });
const { results = {}, total = 0 } = data ?? {};
const handlePageClick = (pageNumber: number) => {
setPage(pageNumber);
};

if (isLoading) {
return (
Expand All @@ -33,10 +41,11 @@ export function GroupView({ isCompact, kqlQuery, sloView, sort, direction }: Pro
}
return (
<>
{data &&
Object.keys(data).map((group) => {
{results &&
Object.keys(results).map((group) => {
return (
<GroupListView
key={group}
sloView={sloView}
group={group}
kqlQuery={kqlQuery}
Expand All @@ -46,6 +55,21 @@ export function GroupView({ isCompact, kqlQuery, sloView, sort, direction }: Pro
/>
);
})}

{total > 0 ? (
<EuiFlexItem>
<EuiTablePagination
pageCount={Math.ceil(total / perPage)}
activePage={page}
onChangePage={handlePageClick}
itemsPerPage={perPage}
itemsPerPageOptions={[25, 50, 100]}
onChangeItemsPerPage={(newPerPage) => {
setPerPage(newPerPage);
}}
/>
</EuiFlexItem>
) : null}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,57 +81,57 @@ export function SloList() {
loading={isLoading || isCreatingSlo || isCloningSlo || isUpdatingSlo || isDeletingSlo}
/>
</EuiFlexItem>

<EuiFlexItem grow={false}>
<ToggleSLOView
sloList={sloList}
sloView={view}
onChangeView={(newView) => onStateChange({ view: newView })}
onToggleCompactView={() => onStateChange({ compact: !isCompact })}
isCompact={isCompact}
/>
</EuiFlexItem>
</EuiFlexGroup>
{groupBy === 'ungrouped' && (
<SlosView
sloList={results}
loading={isLoading || isRefetching}
error={isError}
isCompact={isCompact}

<EuiFlexItem grow={false}>
<ToggleSLOView
sloList={sloList}
sloView={view}
group="ungrouped"
onChangeView={(newView) => onStateChange({ view: newView })}
onToggleCompactView={() => onStateChange({ compact: !isCompact })}
isCompact={isCompact}
/>
</EuiFlexItem>
{groupBy === 'ungrouped' && (
<>
<SlosView
sloList={results}
loading={isLoading || isRefetching}
error={isError}
isCompact={isCompact}
sloView={view}
group="ungrouped"
/>
{total > 0 ? (
<EuiFlexItem>
<EuiTablePagination
pageCount={Math.ceil(total / perPage)}
activePage={page}
onChangePage={(newPage) => {
onStateChange({ page: newPage });
}}
itemsPerPage={perPage}
itemsPerPageOptions={[10, 25, 50, 100]}
onChangeItemsPerPage={(newPerPage) => {
storeState({ perPage: newPerPage, page: 0 });
}}
/>
</EuiFlexItem>
) : null}
</>
)}

{groupBy !== 'ungrouped' && (
<>
<GroupView
sloView={view}
groupBy={groupBy}
isCompact={isCompact}
kqlQuery={state.kqlQuery}
kqlQuery={kqlQuery}
sort={state.sort.by}
direction={state.sort.direction}
/>
</>
)}

{total > 0 ? (
<EuiFlexItem>
<EuiTablePagination
pageCount={Math.ceil(total / perPage)}
activePage={page}
onChangePage={(newPage) => {
onStateChange({ page: newPage });
}}
itemsPerPage={perPage}
itemsPerPageOptions={[10, 25, 50, 100]}
onChangeItemsPerPage={(newPerPage) => {
storeState({ perPage: newPerPage, page: 0 });
}}
/>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
);
}
Loading

0 comments on commit 30706f8

Please sign in to comment.