Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b807203
cleanup form default values initialization logic
kdelemme Nov 18, 2024
83992f5
Use default gap between inputs
kdelemme Nov 18, 2024
05f3955
Move indicators into own folder
kdelemme Nov 18, 2024
9596596
Move advanced settings in own component
kdelemme Nov 18, 2024
e8b9bfd
Add syncDelay advanced settings
kdelemme Nov 18, 2024
9dcfc55
Add sync delay in overview
kdelemme Nov 18, 2024
01425db
Add frequency settings
kdelemme Nov 18, 2024
04c8423
Use grid
kdelemme Nov 18, 2024
c214e12
Introduce syncField settings and use it in transforms
kdelemme Nov 19, 2024
c15af8c
Use syncField when provided
kdelemme Nov 19, 2024
f9c5f20
Handle sync field value
kdelemme Nov 19, 2024
e3011a8
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 19, 2024
cebdf80
Ensure dataview dependant fields are cleared on update
kdelemme Nov 22, 2024
199721e
remove console log
kdelemme Nov 22, 2024
8774b98
Append optional text
kdelemme Nov 22, 2024
7485773
Update locator
kdelemme Nov 22, 2024
17823db
Fix default values when no state provided
kdelemme Nov 22, 2024
0bf8b60
Merge branch 'main' into feat/advanced-settings-slo
kdelemme Nov 25, 2024
887fbb0
Merge branch 'main' into feat/advanced-settings-slo
kdelemme Nov 26, 2024
b2c9133
Merge branch 'main' into feat/advanced-settings-slo
kdelemme Nov 26, 2024
389fcc4
Merge branch 'main' into feat/advanced-settings-slo
kdelemme Nov 27, 2024
4c0e028
Fix invalid state
kdelemme Nov 28, 2024
da345b6
Merge branch 'main' into feat/advanced-settings-slo
shahzad31 Nov 29, 2024
1dd3775
Update x-pack/plugins/observability_solution/slo/public/pages/slo_edi…
kdelemme Dec 2, 2024
3eb4929
Merge branch 'main' into feat/advanced-settings-slo
kdelemme Dec 2, 2024
27e00b0
Remove unecessary parseInt
kdelemme Dec 2, 2024
9a4ce7f
Add syncField in OpenAPI spec
kdelemme Dec 2, 2024
ca6df89
[CI] Auto-commit changed files from 'make api-docs'
kibanamachine Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions x-pack/packages/kbn-slo-schema/src/schema/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,26 @@ const objectiveSchema = t.intersection([
t.partial({ timesliceTarget: t.number, timesliceWindow: durationType }),
]);

const settingsSchema = t.type({
const settingsSchema = t.intersection([
t.type({
syncDelay: durationType,
frequency: durationType,
preventInitialBackfill: t.boolean,
}),
t.partial({ syncField: t.union([t.string, t.null]) }),
]);

const groupBySchema = allOrAnyStringOrArray;

const optionalSettingsSchema = t.partial({
syncDelay: durationType,
frequency: durationType,
preventInitialBackfill: t.boolean,
syncField: t.union([t.string, t.null]),
});

const groupBySchema = allOrAnyStringOrArray;

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

// id cannot contain special characters and spaces
const sloIdSchema = new t.Type<string, string, unknown>(
'sloIdSchema',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
import { EuiFlexGrid, EuiPanel, EuiText, useIsWithinBreakpoints } from '@elastic/eui';
import numeral from '@elastic/numeral';
import { i18n } from '@kbn/i18n';
import { TagsList } from '@kbn/observability-shared-plugin/public';
import {
SLOWithSummaryResponse,
occurrencesBudgetingMethodSchema,
querySchema,
rollingTimeWindowTypeSchema,
SLOWithSummaryResponse,
} from '@kbn/slo-schema';
import React from 'react';
import { TagsList } from '@kbn/observability-shared-plugin/public';
import { DisplayQuery } from './display_query';
import { useKibana } from '../../../../hooks/use_kibana';
import {
BUDGETING_METHOD_OCCURRENCES,
Expand All @@ -26,9 +25,9 @@ import {
toIndicatorTypeLabel,
} from '../../../../utils/slo/labels';
import { ApmIndicatorOverview } from './apm_indicator_overview';
import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview';

import { DisplayQuery } from './display_query';
import { OverviewItem } from './overview_item';
import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview';

export interface Props {
slo: SLOWithSummaryResponse;
Expand Down Expand Up @@ -170,6 +169,19 @@ export function Overview({ slo }: Props) {
}
/>
)}

<OverviewItem
title={i18n.translate('xpack.slo.sloDetails.overview.settings.syncDelay', {
defaultMessage: 'Sync delay',
})}
subtitle={slo.settings.syncDelay}
/>
<OverviewItem
title={i18n.translate('xpack.slo.sloDetails.overview.settings.frequency', {
defaultMessage: 'Frequency',
})}
subtitle={slo.settings.frequency}
/>
Comment on lines +173 to +184

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not spending too much time here since Maciej has some plan for the new overview section

</EuiFlexGrid>
</EuiPanel>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* 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 {
EuiAccordion,
EuiCheckbox,
EuiFieldNumber,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiIcon,
EuiIconTip,
EuiTitle,
useGeneratedHtmlId,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { CreateSLOForm } from '../../../types';
import { SyncFieldSelector } from './sync_field_selector';

export function AdvancedSettings() {
const { control, getFieldState } = useFormContext<CreateSLOForm>();
const preventBackfillCheckbox = useGeneratedHtmlId({ prefix: 'preventBackfill' });
const advancedSettingsAccordion = useGeneratedHtmlId({ prefix: 'advancedSettingsAccordion' });

return (
<EuiAccordion
paddingSize="s"
id={advancedSettingsAccordion}
buttonContent={
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
<EuiFlexItem grow={false}>
<EuiIcon type="controlsVertical" size="m" />
</EuiFlexItem>

<EuiFlexItem>
<EuiTitle size="xxs">
<h3>
{i18n.translate('xpack.slo.sloEdit.settings.advancedSettingsLabel', {
defaultMessage: 'Advanced settings',
})}
</h3>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
}
>
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexGrid columns={3} gutterSize="m">
<EuiFlexItem>
<SyncFieldSelector />
</EuiFlexItem>

<EuiFlexItem>
<EuiFormRow
isInvalid={getFieldState('settings.syncDelay').invalid}
label={
<span>
{i18n.translate('xpack.slo.sloEdit.settings.syncDelay.label', {
defaultMessage: 'Sync delay (in minutes)',
})}{' '}
<EuiIconTip
content={i18n.translate('xpack.slo.sloEdit.settings.syncDelay.tooltip', {
defaultMessage:
'The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m.',
Comment thread
kdelemme marked this conversation as resolved.
Outdated
Comment thread
kdelemme marked this conversation as resolved.
Outdated
})}
position="top"
/>
</span>
}
>
<Controller
name="settings.syncDelay"
defaultValue={1}
control={control}
rules={{ required: true, min: 1, max: 359 }}
render={({ field: { ref, onChange, ...field }, fieldState }) => (
<EuiFieldNumber
{...field}
data-test-subj="sloAdvancedSettingsSyncDelay"
isInvalid={fieldState.invalid}
required
value={field.value}
min={1}
max={359}
step={1}
onChange={(event) => onChange(parseInt(event.target.value, 10))}
/>
)}
/>
</EuiFormRow>
</EuiFlexItem>

<EuiFlexItem>
<EuiFormRow
isInvalid={getFieldState('settings.frequency').invalid}
label={
<span>
{i18n.translate('xpack.slo.sloEdit.settings.frequency.label', {
defaultMessage: 'Frequency (in minutes)',
})}{' '}
<EuiIconTip
content={i18n.translate('xpack.slo.sloEdit.settings.frequency.tooltip', {
defaultMessage:
'The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute.',
})}
position="top"
/>
</span>
}
>
<Controller
name="settings.frequency"
defaultValue={1}
control={control}
rules={{ required: true, min: 1, max: 59 }}
render={({ field: { ref, onChange, ...field }, fieldState }) => (
<EuiFieldNumber
{...field}
data-test-subj="sloAdvancedSettingsFrequency"
isInvalid={fieldState.invalid}
required
value={field.value}
min={1}
max={59}
step={1}
onChange={(event) => onChange(parseInt(event.target.value, 10))}
/>
)}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGrid>

<EuiFormRow isInvalid={getFieldState('settings.preventInitialBackfill').invalid}>
<Controller
name="settings.preventInitialBackfill"
control={control}
render={({ field: { ref, onChange, ...field } }) => (
<EuiCheckbox
id={preventBackfillCheckbox}
label={
<span>
{i18n.translate('xpack.slo.sloEdit.settings.preventInitialBackfill.label', {
defaultMessage: 'Prevent initial backfill of data',
})}{' '}
<EuiIconTip
content={i18n.translate(
'xpack.slo.sloEdit.settings.preventInitialBackfill.tooltip',
{
defaultMessage:
'Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window.',
}
)}
position="top"
/>
</span>
}
checked={Boolean(field.value)}
onChange={(event: any) => onChange(event.target.checked)}
/>
)}
/>
</EuiFormRow>
</EuiFlexGroup>
</EuiAccordion>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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 { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { useCreateDataView } from '../../../../../hooks/use_create_data_view';
import { createOptionsFromFields } from '../../../helpers/create_options';
import { CreateSLOForm } from '../../../types';

const placeholder = i18n.translate('xpack.slo.sloEdit.settings.syncField.placeholder', {
defaultMessage: 'Select a timestamp field',
});

export function SyncFieldSelector() {
const { control, watch, getFieldState } = useFormContext<CreateSLOForm>();
const [index, dataViewId] = watch(['indicator.params.index', 'indicator.params.dataViewId']);
const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({
indexPatternString: index,
dataViewId,
});
const timestampFields = dataView?.fields?.filter((field) => field.type === 'date') ?? [];

return (
<EuiFormRow
label={
<span>
{i18n.translate('xpack.slo.sloEdit.settings.syncField.label', {
defaultMessage: 'Sync field',
})}{' '}
<EuiIconTip
content={i18n.translate('xpack.slo.sloEdit.settings.syncField.tooltip', {
defaultMessage:
'The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field.',
})}
position="top"
/>
</span>
}
isInvalid={getFieldState('settings.syncField').invalid}
>
<Controller
name={'settings.syncField'}
defaultValue={null}
control={control}
rules={{ required: false }}
render={({ field, fieldState }) => {
return (
<EuiComboBox<string>
{...field}
placeholder={placeholder}
aria-label={placeholder}
isClearable
isDisabled={isIndexFieldsLoading}
isInvalid={fieldState.invalid}
isLoading={isIndexFieldsLoading}
onChange={(selected: EuiComboBoxOptionOption[]) => {
if (selected.length) {
return field.onChange(selected[0].value);
}

field.onChange(null);
}}
singleSelection={{ asPlainText: true }}
options={createOptionsFromFields(timestampFields)}
selectedOptions={
!!timestampFields && !!field.value
? [{ value: field.value, label: field.value }]
: []
}
/>
);
}}
/>
</EuiFormRow>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import React from 'react';
import { ComponentStory } from '@storybook/react';
import { FormProvider, useForm } from 'react-hook-form';

import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator';
import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator';
import { ApmAvailabilityIndicatorTypeForm as Component } from './apm_availability_indicator_type_form';
import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants';
import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants';

export default {
component: Component,
Expand Down
Loading