Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into ftr/serverless-user…
Browse files Browse the repository at this point in the history
…-manager
  • Loading branch information
dmlemeshko committed Nov 30, 2023
2 parents 2a94eaf + ab5ff9c commit c478991
Show file tree
Hide file tree
Showing 59 changed files with 1,548 additions and 238 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Delete any items that are not applicable to this PR.
- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials
- [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
- [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,53 @@ describe('grouping container', () => {

expect(renderChildComponent).toHaveBeenCalledWith(getNullGroupFilter('host.name'));
});

it('Renders groupPanelRenderer when provided', () => {
const groupPanelRenderer = jest.fn();
render(
<I18nProvider>
<Grouping {...testProps} groupPanelRenderer={groupPanelRenderer} />
</I18nProvider>
);

expect(groupPanelRenderer).toHaveBeenNthCalledWith(
1,
'host.name',
testProps.data.groupByFields.buckets[0],
undefined,
false
);

expect(groupPanelRenderer).toHaveBeenNthCalledWith(
2,
'host.name',
testProps.data.groupByFields.buckets[1],
undefined,
false
);

expect(groupPanelRenderer).toHaveBeenNthCalledWith(
3,
'host.name',
testProps.data.groupByFields.buckets[2],
'The selected group by field, host.name, is missing a value for this group of events.',
false
);
});
it('Renders groupPanelRenderer when provided with isLoading attribute', () => {
const groupPanelRenderer = jest.fn();
render(
<I18nProvider>
<Grouping {...testProps} isLoading groupPanelRenderer={groupPanelRenderer} />
</I18nProvider>
);

expect(groupPanelRenderer).toHaveBeenNthCalledWith(
1,
'host.name',
testProps.data.groupByFields.buckets[0],
undefined,
true
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ const GroupingComponent = <T,>({
groupBucket={groupBucket}
groupPanelRenderer={
groupPanelRenderer &&
groupPanelRenderer(selectedGroup, groupBucket, nullGroupMessage)
groupPanelRenderer(selectedGroup, groupBucket, nullGroupMessage, isLoading)
}
isLoading={isLoading}
onToggleGroup={(isOpen) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export type GroupStatsRenderer<T> = (
export type GroupPanelRenderer<T> = (
selectedGroup: string,
fieldBucket: RawBucket<T>,
nullGroupMessage?: string
nullGroupMessage?: string,
isLoading?: boolean
) => JSX.Element | undefined;

export type OnGroupToggle = (params: {
Expand Down
34 changes: 33 additions & 1 deletion src/plugins/discover/public/utils/get_sharing_data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
SORT_DEFAULT_ORDER_SETTING,
SEARCH_FIELDS_FROM_SOURCE,
} from '@kbn/discover-utils';
import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
import { buildDataViewMock, dataViewMock } from '@kbn/discover-utils/src/__mocks__';
import { getSharingData, showPublicUrlSwitch } from './get_sharing_data';

describe('getSharingData', () => {
Expand Down Expand Up @@ -162,6 +162,38 @@ describe('getSharingData', () => {
]);
});

test('getSearchSource supports nested fields', async () => {
const index = buildDataViewMock({
name: 'the-data-view',
timeFieldName: 'cool-timefield',
fields: [
...dataViewMock.fields,
{
name: 'cool-field-2.field',
type: 'keyword',
subType: {
nested: {
path: 'cool-field-2.field.path',
},
},
},
] as DataView['fields'],
});
const searchSourceMock = createSearchSourceMock({ index });
const { getSearchSource } = await getSharingData(
searchSourceMock,
{
columns: ['cool-field-1', 'cool-field-2'],
},
services
);
expect(getSearchSource({}).fields).toStrictEqual([
{ field: 'cool-timefield', include_unmapped: 'true' },
{ field: 'cool-field-1', include_unmapped: 'true' },
{ field: 'cool-field-2.*', include_unmapped: 'true' },
]);
});

test('fields have prepended timeField', async () => {
const index = { ...dataViewMock } as DataView;
index.timeFieldName = 'cool-timefield';
Expand Down
13 changes: 12 additions & 1 deletion src/plugins/discover/public/utils/get_sharing_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { Filter } from '@kbn/es-query';
import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public';
import {
DOC_HIDE_TIME_COLUMN_SETTING,
isNestedFieldParent,
SEARCH_FIELDS_FROM_SOURCE,
SORT_DEFAULT_ORDER_SETTING,
} from '@kbn/discover-utils';
Expand Down Expand Up @@ -113,7 +114,17 @@ export async function getSharingData(
if (useFieldsApi) {
searchSource.removeField('fieldsFromSource');
const fields = columns.length
? columns.map((field) => ({ field, include_unmapped: 'true' }))
? columns.map((column) => {
let field = column;

// If this column is a nested field, add a wildcard to the field name in order to fetch
// all leaf fields for the report, since the fields API doesn't support nested field roots
if (isNestedFieldParent(column, index)) {
field = `${column}.*`;
}

return { field, include_unmapped: 'true' };
})
: [{ field: '*', include_unmapped: 'true' }];

searchSource.setField('fields', fields);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ describe('<FollowerIndicesList />', () => {
});
});

describe('detail panel', () => {
// FLAKY: https://github.com/elastic/kibana/issues/142774
describe.skip('detail panel', () => {
test('should open a detail panel when clicking on a follower index', async () => {
expect(exists('followerIndexDetail')).toBe(false);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/*
* 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 { LogicMounter } from '../../../__mocks__/kea_logic';

import { HttpError, Status } from '../../../../../common/types/api';
import { MlModelDeploymentState } from '../../../../../common/types/ml';

import { MlModel } from '../../../../../common/types/ml';

import {
CachedFetchModelsApiLogic,
CachedFetchModelsApiLogicValues,
} from './cached_fetch_models_api_logic';
import { FetchModelsApiLogic } from './fetch_models_api_logic';

const DEFAULT_VALUES: CachedFetchModelsApiLogicValues = {
data: [],
isInitialLoading: false,
isLoading: false,
modelsData: null,
pollTimeoutId: null,
status: Status.IDLE,
};

const FETCH_MODELS_API_DATA_RESPONSE: MlModel[] = [
{
modelId: 'model_1',
title: 'Model 1',
type: 'ner',
deploymentState: MlModelDeploymentState.NotDeployed,
startTime: 0,
targetAllocationCount: 0,
nodeAllocationCount: 0,
threadsPerAllocation: 0,
isPlaceholder: false,
hasStats: false,
},
];
const FETCH_MODELS_API_ERROR_RESPONSE = {
body: {
error: 'Error while fetching models',
message: 'Error while fetching models',
statusCode: 500,
},
} as HttpError;

jest.useFakeTimers();

describe('TextExpansionCalloutLogic', () => {
const { mount } = new LogicMounter(CachedFetchModelsApiLogic);
const { mount: mountFetchModelsApiLogic } = new LogicMounter(FetchModelsApiLogic);

beforeEach(() => {
jest.clearAllMocks();
mountFetchModelsApiLogic();
mount();
});

describe('listeners', () => {
describe('apiError', () => {
it('sets new polling timeout if a timeout ID is already set', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout');

CachedFetchModelsApiLogic.actions.apiError(FETCH_MODELS_API_ERROR_RESPONSE);

expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled();
});
});

describe('apiSuccess', () => {
it('sets new polling timeout if a timeout ID is already set', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout');

CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE);

expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled();
});
});

describe('createPollTimeout', () => {
const duration = 5000;
it('clears polling timeout if it is set', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

jest.spyOn(global, 'clearTimeout');

CachedFetchModelsApiLogic.actions.createPollTimeout(duration);

expect(clearTimeout).toHaveBeenCalledWith('timeout-id');
});
it('sets polling timeout', () => {
jest.spyOn(global, 'setTimeout');
jest.spyOn(CachedFetchModelsApiLogic.actions, 'setTimeoutId');

CachedFetchModelsApiLogic.actions.createPollTimeout(duration);

expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), duration);
expect(CachedFetchModelsApiLogic.actions.setTimeoutId).toHaveBeenCalled();
});
});

describe('startPolling', () => {
it('clears polling timeout if it is set', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

jest.spyOn(global, 'clearTimeout');

CachedFetchModelsApiLogic.actions.startPolling();

expect(clearTimeout).toHaveBeenCalledWith('timeout-id');
});
it('makes API request and sets polling timeout', () => {
jest.spyOn(CachedFetchModelsApiLogic.actions, 'makeRequest');
jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout');

CachedFetchModelsApiLogic.actions.startPolling();

expect(CachedFetchModelsApiLogic.actions.makeRequest).toHaveBeenCalled();
expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled();
});
});

describe('stopPolling', () => {
it('clears polling timeout if it is set', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

jest.spyOn(global, 'clearTimeout');

CachedFetchModelsApiLogic.actions.stopPolling();

expect(clearTimeout).toHaveBeenCalledWith('timeout-id');
});
it('clears polling timeout value', () => {
jest.spyOn(CachedFetchModelsApiLogic.actions, 'clearPollTimeout');

CachedFetchModelsApiLogic.actions.stopPolling();

expect(CachedFetchModelsApiLogic.actions.clearPollTimeout).toHaveBeenCalled();
});
});
});

describe('reducers', () => {
describe('modelsData', () => {
it('gets cleared on API reset', () => {
mount({
...DEFAULT_VALUES,
modelsData: [],
});

CachedFetchModelsApiLogic.actions.apiReset();

expect(CachedFetchModelsApiLogic.values.modelsData).toBe(null);
});
it('gets set on API success', () => {
CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE);

expect(CachedFetchModelsApiLogic.values.modelsData).toEqual(FETCH_MODELS_API_DATA_RESPONSE);
});
});

describe('pollTimeoutId', () => {
it('gets cleared on clear timeout action', () => {
mount({
...DEFAULT_VALUES,
pollTimeoutId: 'timeout-id',
});

CachedFetchModelsApiLogic.actions.clearPollTimeout();

expect(CachedFetchModelsApiLogic.values.pollTimeoutId).toBe(null);
});
it('gets set on set timeout action', () => {
const timeout = setTimeout(() => {}, 500);

CachedFetchModelsApiLogic.actions.setTimeoutId(timeout);

expect(CachedFetchModelsApiLogic.values.pollTimeoutId).toEqual(timeout);
});
});
});

describe('selectors', () => {
describe('isInitialLoading', () => {
it('true if API is idle', () => {
mount(DEFAULT_VALUES);

expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(true);
});
it('true if API is loading for the first time', () => {
mount({
...DEFAULT_VALUES,
status: Status.LOADING,
});

expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(true);
});
it('false if the API is neither idle nor loading', () => {
CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE);

expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(false);
});
});
});
});
Loading

0 comments on commit c478991

Please sign in to comment.