Skip to content

Commit

Permalink
feat(slo): handle tags (#153039)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdelemme authored Mar 20, 2023
1 parent 4d8dac6 commit 8abf46f
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 79 deletions.
27 changes: 18 additions & 9 deletions packages/kbn-slo-schema/src/rest_specs/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import {
objectiveSchema,
optionalSettingsSchema,
settingsSchema,
sloIdSchema,
summarySchema,
tagsSchema,
timeWindowSchema,
} from '../schema';

Expand All @@ -31,23 +33,23 @@ const createSLOParamsSchema = t.type({
budgetingMethod: budgetingMethodSchema,
objective: objectiveSchema,
}),
t.partial({ settings: optionalSettingsSchema }),
t.partial({ settings: optionalSettingsSchema, tags: tagsSchema }),
]),
});

const createSLOResponseSchema = t.type({
id: t.string,
id: sloIdSchema,
});

const deleteSLOParamsSchema = t.type({
path: t.type({
id: t.string,
id: sloIdSchema,
}),
});

const getSLOParamsSchema = t.type({
path: t.type({
id: t.string,
id: sloIdSchema,
}),
});

Expand All @@ -66,7 +68,7 @@ const findSLOParamsSchema = t.partial({
});

const sloResponseSchema = t.type({
id: t.string,
id: sloIdSchema,
name: t.string,
description: t.string,
indicator: indicatorSchema,
Expand All @@ -76,6 +78,7 @@ const sloResponseSchema = t.type({
revision: t.number,
settings: settingsSchema,
enabled: t.boolean,
tags: tagsSchema,
createdAt: dateType,
updatedAt: dateType,
});
Expand All @@ -89,7 +92,7 @@ const getSLOResponseSchema = sloWithSummaryResponseSchema;

const updateSLOParamsSchema = t.type({
path: t.type({
id: t.string,
id: sloIdSchema,
}),
body: t.partial({
name: t.string,
Expand All @@ -99,11 +102,12 @@ const updateSLOParamsSchema = t.type({
budgetingMethod: budgetingMethodSchema,
objective: objectiveSchema,
settings: optionalSettingsSchema,
tags: tagsSchema,
}),
});

const manageSLOParamsSchema = t.type({
path: t.type({ id: t.string }),
path: t.type({ id: sloIdSchema }),
});

const updateSLOResponseSchema = sloResponseSchema;
Expand All @@ -115,8 +119,13 @@ const findSLOResponseSchema = t.type({
results: t.array(sloWithSummaryResponseSchema),
});

const fetchHistoricalSummaryParamsSchema = t.type({ body: t.type({ sloIds: t.array(t.string) }) });
const fetchHistoricalSummaryResponseSchema = t.record(t.string, t.array(historicalSummarySchema));
const fetchHistoricalSummaryParamsSchema = t.type({
body: t.type({ sloIds: t.array(sloIdSchema) }),
});
const fetchHistoricalSummaryResponseSchema = t.record(
sloIdSchema,
t.array(historicalSummarySchema)
);

const getSLODiagnosisParamsSchema = t.type({
path: t.type({ id: t.string }),
Expand Down
9 changes: 8 additions & 1 deletion packages/kbn-slo-schema/src/schema/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ const settingsSchema = t.type({

const optionalSettingsSchema = t.partial({ ...settingsSchema.props });

const tagsSchema = t.array(t.string);

const sloIdSchema = t.string;

const sloSchema = t.type({
id: t.string,
id: sloIdSchema,
name: t.string,
description: t.string,
indicator: indicatorSchema,
Expand All @@ -44,6 +48,7 @@ const sloSchema = t.type({
settings: settingsSchema,
revision: t.number,
enabled: t.boolean,
tags: tagsSchema,
createdAt: dateType,
updatedAt: dateType,
});
Expand All @@ -56,7 +61,9 @@ export {
occurrencesBudgetingMethodSchema,
optionalSettingsSchema,
settingsSchema,
sloIdSchema,
sloSchema,
sloWithSummarySchema,
tagsSchema,
timeslicesBudgetingMethodSchema,
};
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"siem-ui-timeline": "e9d6b3a9fd7af6dc502293c21cbdb309409f3996",
"siem-ui-timeline-note": "13c9d4c142f96624a93a623c6d7cba7e1ae9b5a6",
"siem-ui-timeline-pinned-event": "96a43d59b9e2fc11f12255a0cb47ef0a3d83af4c",
"slo": "9a138b459c7efef7fecfda91f22db8b7655d0e61",
"slo": "06733daaa5fbe331fdf3b515171978aff483ccf2",
"space": "9542afcd6fd71558623c09151e453c5e84b4e5e1",
"spaces-usage-stats": "084bd0f080f94fb5735d7f3cf12f13ec92f36bad",
"synthetics-monitor": "96cc312bfa597022f83dfb3b5d1501e27a73e8d5",
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/observability/public/data/slo/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const baseSlo: Omit<SLOWithSummaryResponse, 'id'> = {
isEstimated: false,
},
},
tags: ['k8s', 'production', 'critical'],
enabled: true,
createdAt: now,
updatedAt: now,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { EuiFlexGroup, EuiPanel } from '@elastic/eui';
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui';
import numeral from '@elastic/numeral';
import { i18n } from '@kbn/i18n';
import { SLOWithSummaryResponse } from '@kbn/slo-schema';
Expand Down Expand Up @@ -38,16 +38,20 @@ export function Overview({ slo }: Props) {
defaultMessage: 'Observed value',
}
)}
subtitle={i18n.translate(
'xpack.observability.slo.sloDetails.overview.observedValueSubtitle',
{
defaultMessage: '{value} (objective is {objective})',
values: {
value: hasNoData ? '-' : numeral(slo.summary.sliValue).format(percentFormat),
objective: numeral(slo.objective.target).format(percentFormat),
},
}
)}
subtitle={
<EuiText size="s">
{i18n.translate(
'xpack.observability.slo.sloDetails.overview.observedValueSubtitle',
{
defaultMessage: '{value} (objective is {objective})',
values: {
value: hasNoData ? '-' : numeral(slo.summary.sliValue).format(percentFormat),
objective: numeral(slo.objective.target).format(percentFormat),
},
}
)}
</EuiText>
}
/>
<OverviewItem
title={i18n.translate(
Expand All @@ -56,7 +60,7 @@ export function Overview({ slo }: Props) {
defaultMessage: 'Indicator type',
}
)}
subtitle={toIndicatorTypeLabel(slo.indicator.type)}
subtitle={<EuiText size="s">{toIndicatorTypeLabel(slo.indicator.type)}</EuiText>}
/>
<OverviewItem
title={i18n.translate('xpack.observability.slo.sloDetails.overview.timeWindowTitle', {
Expand All @@ -71,7 +75,7 @@ export function Overview({ slo }: Props) {
defaultMessage: 'Budgeting method',
}
)}
subtitle={toBudgetingMethodLabel(slo.budgetingMethod)}
subtitle={<EuiText size="s">{toBudgetingMethodLabel(slo.budgetingMethod)}</EuiText>}
/>
</EuiFlexGroup>

Expand All @@ -80,25 +84,42 @@ export function Overview({ slo }: Props) {
title={i18n.translate('xpack.observability.slo.sloDetails.overview.descriptionTitle', {
defaultMessage: 'Description',
})}
subtitle={!!slo.description ? slo.description : '-'}
subtitle={<EuiText size="s">{!!slo.description ? slo.description : '-'}</EuiText>}
/>
<OverviewItem
title={i18n.translate('xpack.observability.slo.sloDetails.overview.createdAtTitle', {
defaultMessage: 'Created at',
})}
subtitle={moment(slo.createdAt).format(dateFormat)}
subtitle={<EuiText size="s">{moment(slo.createdAt).format(dateFormat)}</EuiText>}
/>
<OverviewItem
title={i18n.translate('xpack.observability.slo.sloDetails.overview.updatedAtTitle', {
defaultMessage: 'Last update at',
})}
subtitle={moment(slo.updatedAt).format(dateFormat)}
subtitle={<EuiText size="s">{moment(slo.updatedAt).format(dateFormat)}</EuiText>}
/>
<OverviewItem
title={i18n.translate('xpack.observability.slo.sloDetails.overview.tagsTitle', {
defaultMessage: 'Tags',
})}
subtitle="-"
subtitle={
slo.tags.length > 0 ? (
<EuiFlexGroup
direction="row"
alignItems="flexStart"
gutterSize="s"
responsive={false}
>
{slo.tags.map((tag) => (
<EuiFlexItem grow={false} key={tag}>
<EuiBadge color="hollow">{tag}</EuiBadge>
</EuiFlexItem>
))}
</EuiFlexGroup>
) : (
<EuiText size="s">-</EuiText>
)
}
/>
</EuiFlexGroup>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
*/

import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import React from 'react';
import React, { ReactNode } from 'react';

export interface Props {
title: string;
subtitle: string;
subtitle: ReactNode;
}

export function OverviewItem({ title, subtitle }: Props) {
Expand All @@ -22,9 +22,7 @@ export function OverviewItem({ title, subtitle }: Props) {
<strong>{title}</strong>
</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<EuiText size="s">{subtitle}</EuiText>
</EuiFlexItem>
<EuiFlexItem>{subtitle}</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

import {
EuiComboBox,
EuiComboBoxOptionOption,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -22,6 +24,7 @@ export function SloEditFormDescription() {
const { control } = useFormContext<CreateSLOInput>();
const sloNameId = useGeneratedHtmlId({ prefix: 'sloName' });
const descriptionId = useGeneratedHtmlId({ prefix: 'sloDescription' });
const tagsId = useGeneratedHtmlId({ prefix: 'tags' });

return (
<EuiFlexGroup direction="column" gutterSize="l">
Expand Down Expand Up @@ -80,6 +83,70 @@ export function SloEditFormDescription() {
)}
/>
</EuiFlexItem>

<EuiFlexItem grow>
<EuiFormLabel>
{i18n.translate('xpack.observability.slo.sloEdit.tags.label', {
defaultMessage: 'Tags',
})}
</EuiFormLabel>
<Controller
shouldUnregister={true}
name="tags"
control={control}
defaultValue={[]}
rules={{ required: false }}
render={({ field: { ref, ...field }, fieldState }) => (
<EuiComboBox
{...field}
id={tagsId}
fullWidth
aria-label={i18n.translate('xpack.observability.slo.sloEdit.tags.placeholder', {
defaultMessage: 'Add tags',
})}
placeholder={i18n.translate('xpack.observability.slo.sloEdit.tags.placeholder', {
defaultMessage: 'Add tags',
})}
isInvalid={!!fieldState.error}
options={[]}
noSuggestions
selectedOptions={generateTagOptions(field.value)}
onChange={(selected: EuiComboBoxOptionOption[]) => {
if (selected.length) {
return field.onChange(selected.map((opts) => opts.value));
}

field.onChange([]);
}}
onCreateOption={(searchValue: string, options: EuiComboBoxOptionOption[] = []) => {
const normalizedSearchValue = searchValue.trim().toLowerCase();

if (!normalizedSearchValue) {
return;
}
const values = field.value ?? [];

if (
values.findIndex((tag) => tag.trim().toLowerCase() === normalizedSearchValue) ===
-1
) {
field.onChange([...values, searchValue]);
}
}}
isClearable={true}
data-test-subj="sloEditApmAvailabilityGoodStatusCodesSelector"
/>
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
}

function generateTagOptions(tags: string[] = []) {
return tags.map((tag) => ({
label: tag,
value: tag,
'data-test-subj': `${tag}Option`,
}));
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES: CreateSLOInput = {
TIMEWINDOW_OPTIONS[TIMEWINDOW_OPTIONS.findIndex((option) => option.value === '30d')].value,
isRolling: true,
},
tags: [],
budgetingMethod: BUDGETING_METHOD_OPTIONS[0].value,
objective: {
target: 99.5,
Expand Down
Loading

0 comments on commit 8abf46f

Please sign in to comment.