Skip to content

Commit

Permalink
Merge branch 'main' into feature/142958
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 committed Oct 20, 2022
2 parents f65125d + dba19ee commit 165fe55
Show file tree
Hide file tree
Showing 341 changed files with 18,911 additions and 6,364 deletions.
1 change: 1 addition & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ enabled:
- x-pack/test/functional/apps/lens/group1/config.ts
- x-pack/test/functional/apps/lens/group2/config.ts
- x-pack/test/functional/apps/lens/group3/config.ts
- x-pack/test/functional/apps/lens/open_in_lens/config.ts
- x-pack/test/functional/apps/license_management/config.ts
- x-pack/test/functional/apps/logstash/config.ts
- x-pack/test/functional/apps/management/config.ts
Expand Down
10 changes: 7 additions & 3 deletions .buildkite/pipeline-utils/ci-stats/pick_test_group_run_order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ function getRunGroups(bk: BuildkiteClient, allTypes: RunGroup[], typeName: strin
if (tooLongs.length > 0) {
bk.setAnnotation(
`test-group-too-long:${typeName}`,
'error',
'warning',
[
tooLongs.length === 1
? `The following "${typeName}" config has a duration that exceeds the maximum amount of time desired for a single CI job. Please split it up.`
: `The following "${typeName}" configs have durations that exceed the maximum amount of time desired for a single CI job. Please split them up.`,
? `The following "${typeName}" config has a duration that exceeds the maximum amount of time desired for a single CI job. ` +
`This is not an error, and if you don't own this config then you can ignore this warning. ` +
`If you own this config please split it up ASAP and ask Operations if you have questions about how to do that.`
: `The following "${typeName}" configs have durations that exceed the maximum amount of time desired for a single CI job. ` +
`This is not an error, and if you don't own any of these configs then you can ignore this warning.` +
`If you own any of these configs please split them up ASAP and ask Operations if you have questions about how to do that.`,
'',
...tooLongs.map(({ config, durationMin }) => ` - ${config}: ${durationMin} minutes`),
].join('\n')
Expand Down
16 changes: 12 additions & 4 deletions docs/settings/reporting-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ security is enabled, <<xpack-security-encryptionKey, `xpack.security.encryptionK
Specifies the {time-units}[time] that the reporting poller waits between polling the index for any pending Reporting jobs. Can be specified as number of milliseconds. Defaults to `3s`.

[[xpack-reporting-q-timeout]] `xpack.reporting.queue.timeout` {ess-icon}::
{time-units}[How long] each worker has to produce a report. If your machine is slow or under heavy load, you might need to increase this timeout. If a Reporting job execution goes over this time limit, the job is marked as a failure and no download will be available. Can be specified as number of milliseconds. Defaults to `2m`.
{time-units}[How long] each worker has to produce a report. If your machine is slow or under heavy load, you
might need to increase this timeout. If a Reporting job execution goes over this time limit, the job is marked
as a failure and no download will be available. Can be specified as number of milliseconds. Defaults to `4m`.

[float]
[[reporting-capture-settings]]
Expand All @@ -92,13 +94,19 @@ Specifies the {time-units}[time] that the reporting poller waits between polling
Reporting uses an internal "screenshotting" plugin to capture screenshots from {kib}. The following settings control the capturing process.

`xpack.screenshotting.capture.timeouts.openUrl` {ess-icon}::
Specify the {time-units}[time] to allow the Reporting browser to wait for the "Loading..." screen to dismiss and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current page, and the download link shows a warning message. Can be specified as number of milliseconds. Defaults to `1m`.
Specify the {time-units}[time] to allow the Reporting browser to wait for the "Loading..." screen to dismiss
and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current
page, and the download link shows a warning message. Can be specified as number of milliseconds. Defaults to `1m`.

`xpack.screenshotting.capture.timeouts.waitForElements` {ess-icon}::
Specify the {time-units}[time] to allow the Reporting browser to wait for all visualization panels to load on the page. If the time is exceeded, a screenshot is captured showing the current page, and the download link shows a warning message. Can be specified as number of milliseconds. Defaults to `30s`.
Specify the {time-units}[time] to allow the Reporting browser to wait for all visualization panels to load on
the page. If the time is exceeded, a screenshot is captured showing the current page, and the download link
shows a warning message. Can be specified as number of milliseconds. Defaults to `1m`.

`xpack.screenshotting.capture.timeouts.renderComplete` {ess-icon}::
Specify the {time-units}[time] to allow the Reporting browser to wait for all visualizations to fetch and render the data. If the time is exceeded, a screenshot is captured showing the current page, and the download link shows a warning message. Can be specified as number of milliseconds. Defaults to `30s`.
Specify the {time-units}[time] to allow the Reporting browser to wait for all visualizations to fetch and
render the data. If the time is exceeded, a screenshot is captured showing the current page, and the download
link shows a warning message. Can be specified as number of milliseconds. Defaults to `2m`.

NOTE: If any timeouts from `xpack.screenshotting.capture.timeouts.*` settings occur when
running a report job, Reporting will log the error and try to continue
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@
"prop-types": "^15.8.1",
"proxy-from-env": "1.0.0",
"puid": "1.0.7",
"puppeteer": "^10.2.0",
"puppeteer": "18.1.0",
"query-string": "^6.13.2",
"rbush": "^3.0.1",
"re-resizable": "^6.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,30 @@ describe('FieldComponent', () => {
expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('_source')
);
});

it('it allows custom user input if "acceptsCustomOptions" is "true"', async () => {
const mockOnChange = jest.fn();
const wrapper = render(
<FieldComponent
indexPattern={{
fields,
id: '1234',
title: 'logstash-*',
}}
isClearable={false}
isDisabled={false}
isLoading={false}
onChange={mockOnChange}
placeholder="Placeholder text"
selectedField={undefined}
acceptsCustomOptions
/>
);

const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput');
fireEvent.change(fieldAutocompleteComboBox, { target: { value: 'custom' } });
await waitFor(() =>
expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('custom')
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,18 @@ describe('useField', () => {
]);
});
});
it('should invoke onChange with custom option if one is sent', () => {
const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock }));
act(() => {
result.current.handleCreateCustomOption('madeUpField');
expect(onChangeMock).toHaveBeenCalledWith([
{
name: 'madeUpField',
type: 'text',
},
]);
});
});
});

describe('fieldWidth', () => {
Expand Down
25 changes: 25 additions & 0 deletions packages/kbn-securitysolution-autocomplete/src/field/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const FieldComponent: React.FC<FieldProps> = ({
onChange,
placeholder,
selectedField,
acceptsCustomOptions = false,
}): JSX.Element => {
const {
isInvalid,
Expand All @@ -35,6 +36,7 @@ export const FieldComponent: React.FC<FieldProps> = ({
renderFields,
handleTouch,
handleValuesChange,
handleCreateCustomOption,
} = useField({
indexPattern,
fieldTypeFilter,
Expand All @@ -43,6 +45,29 @@ export const FieldComponent: React.FC<FieldProps> = ({
fieldInputWidth,
onChange,
});

if (acceptsCustomOptions) {
return (
<EuiComboBox
placeholder={placeholder}
options={comboOptions}
selectedOptions={selectedComboOptions}
onChange={handleValuesChange}
isLoading={isLoading}
isDisabled={isDisabled}
isClearable={isClearable}
isInvalid={isInvalid}
onFocus={handleTouch}
singleSelection={AS_PLAIN_TEXT}
data-test-subj="fieldAutocompleteComboBox"
style={fieldWidth}
onCreateOption={handleCreateCustomOption}
customOptionText="Add {searchValue} as your occupation"
fullWidth
/>
);
}

return (
<EuiComboBox
placeholder={placeholder}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface FieldProps extends FieldBaseProps {
isDisabled: boolean;
isLoading: boolean;
placeholder: string;
acceptsCustomOptions?: boolean;
}
export interface FieldBaseProps {
indexPattern: DataViewBase | undefined;
Expand Down
27 changes: 23 additions & 4 deletions packages/kbn-securitysolution-autocomplete/src/field/use_field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,15 @@ export const useField = ({
}: FieldBaseProps) => {
const [touched, setIsTouched] = useState(false);

const { availableFields, selectedFields } = useMemo(
() => getComboBoxFields(indexPattern, selectedField, fieldTypeFilter),
[indexPattern, fieldTypeFilter, selectedField]
);
const [customOption, setCustomOption] = useState<DataViewFieldBase | null>(null);

const { availableFields, selectedFields } = useMemo(() => {
const indexPatternsToUse =
customOption != null && indexPattern != null
? { ...indexPattern, fields: [...indexPattern?.fields, customOption] }
: indexPattern;
return getComboBoxFields(indexPatternsToUse, selectedField, fieldTypeFilter);
}, [indexPattern, fieldTypeFilter, selectedField, customOption]);

const { comboOptions, labels, selectedComboOptions, disabledLabelTooltipTexts } = useMemo(
() => getComboBoxProps({ availableFields, selectedFields }),
Expand All @@ -117,6 +122,19 @@ export const useField = ({
[availableFields, labels, onChange]
);

const handleCreateCustomOption = useCallback(
(val: string) => {
const normalizedSearchValue = val.trim().toLowerCase();

if (!normalizedSearchValue) {
return;
}
setCustomOption({ name: val, type: 'text' });
onChange([{ name: val, type: 'text' }]);
},
[onChange]
);

const handleTouch = useCallback((): void => {
setIsTouched(true);
}, [setIsTouched]);
Expand Down Expand Up @@ -161,5 +179,6 @@ export const useField = ({
renderFields,
handleTouch,
handleValuesChange,
handleCreateCustomOption,
};
};
18 changes: 14 additions & 4 deletions packages/kbn-securitysolution-exception-list-components/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# @kbn/securitysolution-exception-list-components

This is where the building UI components of the Exception-List live
Most of the components here are imported from `x-pack/plugins/security_solutions/public/detection_engine`
Common exceptions' components

# Aim

TODO
- To have most of the Exceptions' components in one place, to be shared accross multiple pages and used for different logic.
- This `package` holds the presetational part of the components only as the API or the logic part should reside under the consumer page

# Pattern used

Expand All @@ -14,9 +14,19 @@ component
index.tsx
index.styles.ts <-- to hold styles if the component has many custom styles
use_component.ts <-- for logic if the Presentational Component has logic
index.test.tsx
component.test.tsx
use_component.test.tsx
```
# Testing

In order to unify our testing tools, we configured only two libraries, the `React-Testing-Library` to test the component UI part and the `Reat-Testing-Hooks` to test the component's UI interactions

# Styling

In order to follow the `KBN-Packages's` recommendations, to define a custom CSS we can only use the `@emotion/react` or `@emotion/css` libraries



# Next

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
* Side Public License, v 1.
*/

export * from './src/search_bar/search_bar';
export * from './src/empty_viewer_state/empty_viewer_state';
export * from './src/search_bar';
export * from './src/empty_viewer_state';
export * from './src/pagination/pagination';
// export * from './src/exceptions_utility/exceptions_utility';
export * from './src/exception_items/exception_items';
export * from './src/exception_items';
export * from './src/exception_item_card';
export * from './src/value_with_space_warning';
export * from './src/types';
export * from './src/list_header';
export * from './src/header_menu';
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ module.exports = {
collectCoverageFrom: [
'<rootDir>/packages/kbn-securitysolution-exception-list-components/**/*.{ts,tsx}',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/*.test',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/types/*',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/*.type',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/*.styles',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/mocks/*',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/*.config',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/translations',
'!<rootDir>/packages/kbn-securitysolution-exception-list-components/**/types/*',
],
setupFilesAfterEnv: [
'<rootDir>/packages/kbn-securitysolution-exception-list-components/setup_test.ts',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
import React from 'react';
import { render } from '@testing-library/react';

import { EmptyViewerState } from './empty_viewer_state';
import { EmptyViewerState } from '.';
import { ListTypeText, ViewerStatus } from '../types';
import * as i18n from '../translations';

describe('EmptyViewerState', () => {
it('it should render "error" with the default title and body', () => {
Expand All @@ -23,10 +24,10 @@ describe('EmptyViewerState', () => {
);

expect(wrapper.getByTestId('errorViewerState')).toBeTruthy();
expect(wrapper.getByTestId('errorTitle')).toHaveTextContent('Unable to load exception items');
expect(wrapper.getByTestId('errorBody')).toHaveTextContent(
'There was an error loading the exception items. Contact your administrator for help.'
expect(wrapper.getByTestId('errorTitle')).toHaveTextContent(
i18n.EMPTY_VIEWER_STATE_ERROR_TITLE
);
expect(wrapper.getByTestId('errorBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_ERROR_BODY);
});
it('it should render "error" when sending the title and body props', () => {
const wrapper = render(
Expand Down Expand Up @@ -65,9 +66,11 @@ describe('EmptyViewerState', () => {

expect(wrapper.getByTestId('emptySearchViewerState')).toBeTruthy();
expect(wrapper.getByTestId('emptySearchTitle')).toHaveTextContent(
'No results match your search criteria'
i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE
);
expect(wrapper.getByTestId('emptySearchBody')).toHaveTextContent(
i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY
);
expect(wrapper.getByTestId('emptySearchBody')).toHaveTextContent('Try modifying your search');
});
it('it should render empty search when sending title and body props', () => {
const wrapper = render(
Expand Down Expand Up @@ -111,11 +114,11 @@ describe('EmptyViewerState', () => {

const { getByTestId } = wrapper;
expect(getByTestId('emptyViewerState')).toBeTruthy();
expect(getByTestId('emptyTitle')).toHaveTextContent('Add exceptions to this rule');
expect(getByTestId('emptyBody')).toHaveTextContent(
'There is no exception in your rule. Create your first rule exception.'
expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE);
expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY);
expect(getByTestId('emptyStateButton')).toHaveTextContent(
i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON('rule')
);
expect(getByTestId('emptyStateButton')).toHaveTextContent('Create rule exception');
});
it('it should render no items screen with default title and body props and listType endPoint', () => {
const wrapper = render(
Expand All @@ -129,10 +132,29 @@ describe('EmptyViewerState', () => {

const { getByTestId } = wrapper;
expect(getByTestId('emptyViewerState')).toBeTruthy();
expect(getByTestId('emptyTitle')).toHaveTextContent('Add exceptions to this rule');
expect(getByTestId('emptyBody')).toHaveTextContent(
'There is no exception in your rule. Create your first rule exception.'
expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE);
expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY);
expect(getByTestId('emptyStateButton')).toHaveTextContent(
i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(ListTypeText.ENDPOINT)
);
});
it('it should render no items screen and disable the Create exception button if isReadOnly true', () => {
const wrapper = render(
<EmptyViewerState
isReadOnly={true}
viewerStatus={ViewerStatus.EMPTY}
onCreateExceptionListItem={jest.fn()}
listType={ListTypeText.ENDPOINT}
/>
);

const { getByTestId } = wrapper;
expect(getByTestId('emptyViewerState')).toBeTruthy();
expect(getByTestId('emptyTitle')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE);
expect(getByTestId('emptyBody')).toHaveTextContent(i18n.EMPTY_VIEWER_STATE_EMPTY_BODY);
expect(getByTestId('emptyStateButton')).toHaveTextContent(
i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(ListTypeText.ENDPOINT)
);
expect(getByTestId('emptyStateButton')).toHaveTextContent('Create endpoint exception');
expect(getByTestId('emptyStateButton')).toBeDisabled();
});
});
Loading

0 comments on commit 165fe55

Please sign in to comment.