[8.16] [ResponseOps] Do not change time field when edit (#206858) (#208029)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[ResponseOps] Do not change time field when edit
(#206858)](https://github.com/elastic/kibana/pull/206858)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"Julia","email":"iuliia.guskova@elastic.co"},"sourceCommit":{"committedDate":"2025-01-23T11:38:15Z","message":"[ResponseOps]
Do not change time field when edit (#206858)\n\nFixed:
https://github.com/elastic/kibana/issues/204432\r\n\r\nHow to
test:\r\nGo to rules creation. Create ESquery rule. Set some
`@timestamp` time\r\nfield. Try to edit rule. Check if it's save
previous value of time\r\nfield.\r\n\r\nCheck the PR satisfies following
conditions. \r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"993392bc4f6a96391644578a77bc2c4406581d05","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Alerting","release_note:skip","Team:ResponseOps","v9.0.0","backport:prev-major","v8.18.0"],"title":"[ResponseOps]
Do not change time field when
edit","number":206858,"url":"https://github.com/elastic/kibana/pull/206858","mergeCommit":{"message":"[ResponseOps]
Do not change time field when edit (#206858)\n\nFixed:
https://github.com/elastic/kibana/issues/204432\r\n\r\nHow to
test:\r\nGo to rules creation. Create ESquery rule. Set some
`@timestamp` time\r\nfield. Try to edit rule. Check if it's save
previous value of time\r\nfield.\r\n\r\nCheck the PR satisfies following
conditions. \r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"993392bc4f6a96391644578a77bc2c4406581d05"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/206858","number":206858,"mergeCommit":{"message":"[ResponseOps]
Do not change time field when edit (#206858)\n\nFixed:
https://github.com/elastic/kibana/issues/204432\r\n\r\nHow to
test:\r\nGo to rules creation. Create ESquery rule. Set some
`@timestamp` time\r\nfield. Try to edit rule. Check if it's save
previous value of time\r\nfield.\r\n\r\nCheck the PR satisfies following
conditions. \r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"993392bc4f6a96391644578a77bc2c4406581d05"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Julia <iuliia.guskova@elastic.co>
This commit is contained in:
Kibana Machine 2025-01-24 00:31:44 +11:00 committed by GitHub
parent 95a0980e2a
commit b09bca4439
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 102 additions and 30 deletions

View file

@ -6,9 +6,8 @@
*/
import React, { PropsWithChildren } from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { fireEvent, render, waitFor, screen, act } from '@testing-library/react';
import { I18nProvider } from '@kbn/i18n-react';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
@ -24,6 +23,40 @@ const { hasExpressionValidationErrors } = jest.requireMock('../validation');
jest.mock('@kbn/esql-editor', () => ({
fetchFieldsFromESQL: jest.fn(),
}));
jest.mock('@kbn/triggers-actions-ui-plugin/public', () => {
const module = jest.requireActual('@kbn/kibana-react-plugin/public');
return {
...module,
getFields: jest.fn().mockResolvedValue([]),
};
});
jest.mock('@kbn/triggers-actions-ui-plugin/public/common', () => {
const module = jest.requireActual('@kbn/triggers-actions-ui-plugin/public/common');
return {
...module,
getTimeOptions: jest.fn(),
firstFieldOption: { text: '@timestamp', value: '@timestamp' },
getTimeFieldOptions: jest.fn().mockReturnValue([
{ value: '@timestamp', text: '@timestamp' },
{ value: 'event.ingested', text: 'event.ingested' },
]),
};
});
jest.mock('@kbn/esql-utils', () => {
return {
getESQLResults: jest.fn().mockResolvedValue({}),
getIndexPattern: jest.fn(),
getIndexPatternFromESQLQuery: jest.fn().mockReturnValue('index1'),
getESQLAdHocDataview: jest
.fn()
.mockResolvedValue({ timeFieldName: '@timestamp', getIndexPattern: jest.fn() }),
formatESQLColumns: jest.fn().mockReturnValue([]),
};
});
const { fetchFieldsFromESQL } = jest.requireMock('@kbn/esql-editor');
const { getFields } = jest.requireMock('@kbn/triggers-actions-ui-plugin/public');
@ -58,6 +91,39 @@ describe('EsqlQueryRuleTypeExpression', () => {
hasExpressionValidationErrors.mockReturnValue(false);
});
test('should render EsqlQueryRuleTypeExpression with chosen time field', async () => {
await act(async () => {
render(
<EsqlQueryExpression
unifiedSearch={unifiedSearchMock}
ruleInterval="1m"
ruleThrottle="1m"
alertNotifyWhen="onThrottleInterval"
ruleParams={{
...defaultEsqlQueryExpressionParams,
timeField: 'event.ingested',
esqlQuery: { esql: 'FROM *' },
}}
setRuleParams={() => {}}
setRuleProperty={() => {}}
errors={{ esqlQuery: [], timeField: [], timeWindowSize: [] }}
data={dataMock}
dataViews={dataViewMock}
defaultActionGroupId=""
actionGroups={[]}
charts={chartsStartMock}
onChangeMetaData={() => {}}
/>,
{
wrapper: AppWrapper,
}
);
});
const timeFieldText = await screen.findByText('event.ingested');
expect(timeFieldText).toBeInTheDocument();
});
it('should render EsqlQueryRuleTypeExpression with expected components', () => {
const result = render(
<EsqlQueryExpression
@ -135,7 +201,8 @@ describe('EsqlQueryRuleTypeExpression', () => {
],
});
getFields.mockResolvedValue([]);
const result = render(
render(
<EsqlQueryExpression
unifiedSearch={unifiedSearchMock}
ruleInterval="1m"
@ -157,12 +224,12 @@ describe('EsqlQueryRuleTypeExpression', () => {
}
);
fireEvent.click(result.getByTestId('testQuery'));
fireEvent.click(screen.getByTestId('testQuery'));
await waitFor(() => expect(fetchFieldsFromESQL).toBeCalled());
expect(result.getByTestId('testQuerySuccess')).toBeInTheDocument();
expect(result.getByText('Query matched 1 documents in the last 15s.')).toBeInTheDocument();
expect(result.queryByTestId('testQueryError')).not.toBeInTheDocument();
expect(screen.getByTestId('testQuerySuccess')).toBeInTheDocument();
expect(screen.getByText('Query matched 1 documents in the last 15s.')).toBeInTheDocument();
expect(screen.queryByTestId('testQueryError')).not.toBeInTheDocument();
});
test('should show error message if Test Query is throws error', async () => {

View file

@ -60,7 +60,7 @@ export const EsqlQueryExpression: React.FC<
// The sourceFields param is ignored for the ES|QL type
sourceFields: [],
});
const [query, setQuery] = useState<AggregateQuery>({ esql: '' });
const [query, setQuery] = useState<AggregateQuery>(esqlQuery ?? { esql: '' });
const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]);
const [detectedTimestamp, setDetectedTimestamp] = useState<string | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(false);
@ -76,18 +76,13 @@ export const EsqlQueryExpression: React.FC<
[setRuleParams]
);
const setDefaultExpressionValues = async () => {
const setDefaultExpressionValues = () => {
setRuleProperty('params', currentRuleParams);
setQuery(esqlQuery ?? { esql: '' });
if (esqlQuery) {
if (esqlQuery.esql) {
refreshTimeFields(esqlQuery);
}
}
if (timeField) {
setTimeFieldOptions([firstFieldOption, { text: timeField, value: timeField }]);
if (esqlQuery?.esql) {
refreshTimeFields(esqlQuery);
}
};
useEffect(() => {
setDefaultExpressionValues();
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -159,20 +154,30 @@ export const EsqlQueryExpression: React.FC<
isServerless,
]);
const refreshTimeFields = async (q: AggregateQuery) => {
const esqlDataView = await getESQLAdHocDataview(q.esql, dataViews);
const indexPattern: string = esqlDataView.getIndexPattern();
const currentEsFields = await getFields(http, [indexPattern]);
const refreshTimeFields = useCallback(
async (q: AggregateQuery) => {
const fetchTimeFieldsData = async (queryObj: AggregateQuery) => {
try {
const esqlDataView = await getESQLAdHocDataview(queryObj.esql, dataViews);
const indexPattern: string = esqlDataView.getIndexPattern();
const currentEsFields = await getFields(http, [indexPattern]);
const newTimeFieldOptions = getTimeFieldOptions(currentEsFields);
const timestampField = esqlDataView.timeFieldName;
return { newTimeFieldOptions, timestampField };
} catch (e) {
return { newTimeFieldOptions: [], timestampField: undefined };
}
};
const timeFields = getTimeFieldOptions(currentEsFields);
setTimeFieldOptions([firstFieldOption, ...timeFields]);
const timestampField = esqlDataView.timeFieldName;
if (timestampField) {
setParam('timeField', timestampField);
}
setDetectedTimestamp(timestampField);
};
const { newTimeFieldOptions, timestampField } = await fetchTimeFieldsData(q);
setTimeFieldOptions([firstFieldOption, ...newTimeFieldOptions]);
if (!timeField && timestampField) {
setParam('timeField', timestampField);
}
setDetectedTimestamp(timestampField);
},
[timeField, setParam, dataViews, http]
);
return (
<Fragment>