mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# 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:
parent
95a0980e2a
commit
b09bca4439
2 changed files with 102 additions and 30 deletions
|
@ -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 () => {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue